From 649b307604b088574a09b0e1360df5d52f366d21 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Sat, 5 Oct 2024 23:19:10 +1300 Subject: [PATCH] Fix Arithmetic lossless scans truncating with DNL markers. If a scan runs out of arithmetic bits and we are on the start of a line the decoder stops decoding even though the rest of the line may still be valid, just not require any bits. Instead, when we receive the DNL update the image height and continue processing as normal. --- codestream/aclosslessscan.cpp | 6 ++---- codestream/acrefinementscan.hpp | 6 +++++- codestream/acsequentialscan.hpp | 4 ++++ codestream/entropyparser.cpp | 1 + codestream/entropyparser.hpp | 6 +++++- codestream/jpeglsscan.hpp | 6 +++++- codestream/losslessscan.cpp | 6 ++---- codestream/predictivescan.cpp | 9 +++++++++ codestream/predictivescan.hpp | 4 ++++ codestream/refinementscan.hpp | 4 ++++ codestream/sequentialscan.hpp | 4 ++++ 11 files changed, 45 insertions(+), 11 deletions(-) diff --git a/codestream/aclosslessscan.cpp b/codestream/aclosslessscan.cpp index cbfd282..e461838 100644 --- a/codestream/aclosslessscan.cpp +++ b/codestream/aclosslessscan.cpp @@ -467,7 +467,6 @@ bool ACLosslessScan::ParseMCU(void) // Loop over lines and columns do { - bool startofline = true; do { if (BeginReadMCU(m_Coder.ByteStreamOf())) { ParseMCU(prev,top); @@ -475,15 +474,14 @@ bool ACLosslessScan::ParseMCU(void) // Only if this is not due to a DNL marker that has been detected. if (m_ulPixelHeight != 0 && !hasFoundDNL()) { ClearMCU(top); - } else if (!startofline) { + } else { // The problem is here that the DNL marker might have been detected, even though decoding // is not yet done completely. This may be because there are still just enough bits in the // AC coding engine present to run a single decode. Big Outch! Just continue decoding in // this case. ParseMCU(prev,top); - } else break; + } } - startofline = false; } while(AdvanceToTheRight()); // // Reset conditioning to the left diff --git a/codestream/acrefinementscan.hpp b/codestream/acrefinementscan.hpp index 6dff925..d88fdda 100644 --- a/codestream/acrefinementscan.hpp +++ b/codestream/acrefinementscan.hpp @@ -204,7 +204,11 @@ class ACRefinementScan : public EntropyParser { virtual bool ParseMCU(void); // // Write a single MCU in this scan. - virtual bool WriteMCU(void); + virtual bool WriteMCU(void); + // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + virtual void PostImageHeight(ULONG) {} // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. diff --git a/codestream/acsequentialscan.hpp b/codestream/acsequentialscan.hpp index fbe7941..389e9a2 100644 --- a/codestream/acsequentialscan.hpp +++ b/codestream/acsequentialscan.hpp @@ -355,6 +355,10 @@ class ACSequentialScan : public EntropyParser { // Write a single MCU in this scan. virtual bool WriteMCU(void); // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + virtual void PostImageHeight(ULONG) {} + // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. virtual void OptimizeBlock(LONG bx,LONG by,UBYTE component,double critical, diff --git a/codestream/entropyparser.cpp b/codestream/entropyparser.cpp index 5b3858c..d7b11ef 100644 --- a/codestream/entropyparser.cpp +++ b/codestream/entropyparser.cpp @@ -235,6 +235,7 @@ bool EntropyParser::ParseDNLMarker(class ByteStream *io) JPG_THROW(MALFORMED_STREAM,"EntropyParser::ParseDNLMarker", "frame height as indicated by the DNL marker is corrupt, must be > 0"); + PostImageHeight(dt); m_pFrame->PostImageHeight(dt); m_bDNLFound = true; diff --git a/codestream/entropyparser.hpp b/codestream/entropyparser.hpp index b583e98..dac7ef9 100644 --- a/codestream/entropyparser.hpp +++ b/codestream/entropyparser.hpp @@ -211,7 +211,11 @@ class EntropyParser : public JKeeper { virtual bool ParseMCU(void) = 0; // // Write a single MCU in this scan. - virtual bool WriteMCU(void) = 0; + virtual bool WriteMCU(void) = 0; + // + // Define the image size if it is not yet known here. This is + // called whenever the DNL marker is parsed in. + virtual void PostImageHeight(ULONG height) = 0; // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. This runs an optimization for a single diff --git a/codestream/jpeglsscan.hpp b/codestream/jpeglsscan.hpp index 324a8f4..62d3b9f 100644 --- a/codestream/jpeglsscan.hpp +++ b/codestream/jpeglsscan.hpp @@ -695,7 +695,11 @@ class JPEGLSScan : public EntropyParser { virtual bool ParseMCU(void) = 0; // // Write a single MCU in this scan. - virtual bool WriteMCU(void) = 0; + virtual bool WriteMCU(void) = 0; + // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + virtual void PostImageHeight(ULONG) {} // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. diff --git a/codestream/losslessscan.cpp b/codestream/losslessscan.cpp index 6fd9c93..2b4e6dc 100644 --- a/codestream/losslessscan.cpp +++ b/codestream/losslessscan.cpp @@ -432,7 +432,6 @@ bool LosslessScan::ParseMCU(void) // Loop over lines and columns do { - bool startofline = true; do { if (BeginReadMCU(m_Stream.ByteStreamOf())) { ParseMCU(prev,top); @@ -440,14 +439,13 @@ bool LosslessScan::ParseMCU(void) // Only if this is not due to a DNL marker that has been detected. if (m_ulPixelHeight != 0 && !hasFoundDNL()) { ClearMCU(top); - } else if (!startofline) { + } else { // The problem is here that the DNL marker might have been detected, even though decoding // is not yet done completely. This may be because there are still just enough bits in the // bitream present to run a single decode. Big Outch! Just continue decoding in this case. ParseMCU(prev,top); - } else break; + } } - startofline = false; } while(AdvanceToTheRight()); // // Advance to the next line. diff --git a/codestream/predictivescan.cpp b/codestream/predictivescan.cpp index 1bbd86f..df03075 100644 --- a/codestream/predictivescan.cpp +++ b/codestream/predictivescan.cpp @@ -206,6 +206,15 @@ void PredictiveScan::RestartOnMarker(void) } /// +/// PredictiveScan::PostImageHeight +// Post the height of the frame in lines. This happens +// when the DNL marker is processed. +void PredictiveScan::PostImageHeight(ULONG height) +{ + m_ulPixelHeight = height; +} +/// + /// PredictiveScan::OptimizeBlock // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. diff --git a/codestream/predictivescan.hpp b/codestream/predictivescan.hpp index 639b089..9585056 100644 --- a/codestream/predictivescan.hpp +++ b/codestream/predictivescan.hpp @@ -196,6 +196,10 @@ class PredictiveScan : public EntropyParser { // of the restart interval. void RestartOnMarker(void); // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + void PostImageHeight(ULONG height); + // // Start making an optimization run to adjust the coefficients. virtual void StartOptimizeScan(class BufferCtrl *ctrl); // diff --git a/codestream/refinementscan.hpp b/codestream/refinementscan.hpp index 5c29145..9155650 100644 --- a/codestream/refinementscan.hpp +++ b/codestream/refinementscan.hpp @@ -178,6 +178,10 @@ class RefinementScan : public EntropyParser { // Write a single MCU in this scan. virtual bool WriteMCU(void); // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + virtual void PostImageHeight(ULONG) {} + // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. virtual void OptimizeBlock(LONG bx,LONG by,UBYTE component,double critical, diff --git a/codestream/sequentialscan.hpp b/codestream/sequentialscan.hpp index adf6aa2..1dbfc48 100644 --- a/codestream/sequentialscan.hpp +++ b/codestream/sequentialscan.hpp @@ -206,6 +206,10 @@ class SequentialScan : public EntropyParser { // Write a single MCU in this scan. virtual bool WriteMCU(void); // + // Post the height of the frame in lines. This happens + // when the DNL marker is processed. + virtual void PostImageHeight(ULONG) {} + // // Make an R/D optimization for the given scan by potentially pushing // coefficients into other bins. This runs an optimization for a single // block and requires external control to run over the blocks.