Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for high throughput (HTJ2K) decoding. #1374

Closed
wants to merge 12 commits into from

Conversation

aous72
Copy link
Contributor

@aous72 aous72 commented Sep 2, 2021

Hello Everyone,

This is my contribution to the OpenJPEG library. I have integrated high throughput (HTJ2K) decoding to the library. This is achieved with minimal changes to the library.

Kind regards,
Aous

Copy link
Collaborator

@rouault rouault left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Just a few comments from a very quick look at the code.
You'd also want to run ./scripts/prepare-commit.sh to reformat the code with the formatting rules we use. You'll need to build with -DWITH_ASTYLE=ON

src/lib/openjp2/j2k.c Outdated Show resolved Hide resolved
if ((l_tccp->cblksty & 0x80U) != 0 || (l_tccp->cblksty & 0x48U) == 0x48U) {
/* For HT, we only support one mode, bit 6 set, meaning that "all code-blocks
within the corresponding tile-component shall be HT code-blocks, and
bit 3 is reset, meaning that "No vertically causal context". */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is Vertically causal context really invalid, or just not supported ? my reading of the spec is that it is valid (would supporting it would require a lot of changes)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vertically casual is a valid option, but it is not supported in my code yet. I am not sure how much work is needed. I would like to revisit this issue later, if possible.


if (cblk->numbps == 1 && num_passes > 1)
{
// We do not have enough precision to decode SgnProp nor MagRef passes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it an implementation limitation or something wrong with the code stream ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of protection of the block decoder against calls with incorrect configuration. In normal operation cblk->numbps cannot be smaller than 1, unless something is wrong.

Copy link
Contributor Author

@aous72 aous72 Sep 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some where in the email I received there was a message about 3 coding passes.

HT bitstreams usually have 1, 2, or 3 passes; these are a CUP, and possibly SPP and MRP passes. HT supports more than 3 coding passes, but these may occur in transcoding from normal JPEG2000 to HT; it is totally up to the transcoder to generate them or not. If they exist, only the last CUP, and if SPP and MRP exist after it, need to be decoded; the earlier passes are placeholder passes, if anyone needs to transcode from HT back to normal JPEG2000. I have not paid a lot of attention to the case of coding passes before that last CUP. I believe there are also some flags to signal this case.

As far as I know, Kakadu can decode the case of may passes, but I am not very sure if it can generate them.

}
if (cblk->numbps == 0)
{
// We do not have enough precision to decode the CUP pass with the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it an implementation limitation or something wrong with the code stream ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same with the above. If numbps == 0 means there is not bitplanes to decode.

@aous72
Copy link
Contributor Author

aous72 commented Sep 3, 2021

Thank you for your comments. Please let me know if you have further questions.

@Jamaika1
Copy link
Contributor

Jamaika1 commented Sep 12, 2021

OpenHTJ2K version 0 no thread C++14
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Stiles={1563,1558} Clevels=3 Corder=CPRL Creversible=Bool
dopen_j2k.exe -i image_21447_24bit-jhc.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 2 has been read.
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped.
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/2
ERROR -> opj_decompress: failed to decode image!

OpenJPH Ver 0.7.3 no thread
htj2k-cjph.exe -i image_21447_24bit.yuv -o image_21447_24bit-jph.j2c -dims {1563,1558} -num_comps 3 -signed false -bit_depth 8 -downsamp {1,1},{1,1},{1,1} -block_size {64,64} -precincts {128,128},{256,256} -prog_order CPRL -reversible true
dopen_j2k.exe -i image_21447_24bit-jph.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.

Error. Codec doesn't create PNG file
Grok version 9.4.0 thread=1
htj2k-cgrok.exe -v -i image_21447_24bit.raw -o image_21447_24bit-grok.j2k -H 1 -M 64 -F 1563,1558,3,8,u@1x1:1x1:1x1 -mct 1 -b 64,64 -c [128,128],[256,256] -p CPRL -r 1
dopen_j2k.exe -i image_21447_24bit-grok.j2k -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Generated Outfile xxx.png
decode time: 194 ms

OK Codec creates PNG file
Grok version 9.4.0 EXIF thread=1
htj2k-cgrok.exe -v -i L1004432.tiff -o L1004432.jp2 -H 1 -M 64 -r 1
dopen_j2k.exe -i L1004432.jp2 -o xxx.png

[INFO] Start to read j2k main header (8014).
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Stream reached its end !
color.c:564:color_apply_icc_profile
        channels(3) prec(8) w(5212) h(3468)
        profile: in(0000015799cbd870) out(000001579c5df750)
        render_intent (0)
        color_space: in(0x58595a20)(XYZ )   out:(0x52474220)(RGB )
               type: in(262169)              out:(262169)
[INFO] Generated Outfile xxx.png
decode time: 5926 ms

OK Codec creates PNG file

@aous72
Copy link
Contributor Author

aous72 commented Sep 12, 2021

@Jamaika1 I do not understand what you are trying to say. Could you please give more details, and perhaps the image.

@Jamaika1
Copy link
Contributor

Jamaika1 commented Sep 12, 2021

Wait minute. In moment I will add codecs in the forum for the curious in the latest GCC 12.0.0.
https://forum.doom9.org/showthread.php?t=174300&page=23
Codecs.
https://www.sendspace.com/file/0nl2iw
Image
https://www.sendspace.com/filegroup/60mGdt3%2FPQ91zIfg5G3jKp7BDB5tTv1t

@rouault
Copy link
Collaborator

rouault commented Sep 12, 2021

@aous72 I get a crash when decoding a HTJ2K image generated by OpenJPH master:

Given https://github.com/uclouvain/openjpeg-data/blob/master/input/nonregression/Bretagne1.ppm,

ojph_compress -i ~/openjpeg/openjpeg/data/input/nonregression/Bretagne1.ppm -o /tmp/ojph_bretagne1.j2k

and then with your openjpeg HTJ2K capable branch:

$ valgrind bin/opj_decompress -i /tmp/ojph_bretagne1.j2k -o out.ppm
==3979605== Memcheck, a memory error detector
==3979605== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3979605== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==3979605== Command: bin/opj_decompress -i /tmp/ojph_bretagne1.j2k -o out.ppm
==3979605==

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
==3979605== Invalid write of size 4
==3979605== at 0x4859FEC: opj_t1_ht_decode_cblk (fbc_dec.c:1765)
==3979605== by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==3979605== by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==3979605== by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==3979605== by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==3979605== by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==3979605== by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)
==3979605== by 0x4881CDA: opj_j2k_decode_tiles (j2k.c:11566)
==3979605== by 0x487B333: opj_j2k_exec (j2k.c:8903)
==3979605== by 0x4882AD1: opj_j2k_decode (j2k.c:11912)
==3979605== by 0x488EF5C: opj_decode (openjpeg.c:494)
==3979605== by 0x1103AC: main (opj_decompress.c:1547)
==3979605== Address 0x56a0d80 is 0 bytes after a block of size 1,200 alloc'd
==3979605== at 0x483E0F0: memalign (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3979605== by 0x483E212: posix_memalign (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3979605== by 0x48C03FD: opj_aligned_alloc_n (opj_malloc.c:61)
==3979605== by 0x48C05A7: opj_aligned_malloc (opj_malloc.c:209)
==3979605== by 0x48581E7: opj_t1_allocate_buffers (fbc_dec.c:1004)
==3979605== by 0x4858422: opj_t1_ht_decode_cblk (fbc_dec.c:1101)
==3979605== by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==3979605== by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==3979605== by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==3979605== by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==3979605== by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==3979605== by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)

@aous72
Copy link
Contributor Author

aous72 commented Sep 12, 2021

@rouault Thank you Even.
A quick look shows that the problem happens in multi-threaded environment; it does not happen when -threads 1.
I will have a deeper look, first thing tomorrow morning, Sydney Time, and come back to you.

@rouault
Copy link
Collaborator

rouault commented Sep 12, 2021

I found another issue, or perhaps 2, with the ds0_ht_02_b11.j2k file from https://github.com/osamu620/OpenHTJ2K/blob/main/conformance_data/ds0_ht_02_b11.j2k:

$ valgrind bin/opj_decompress -i ~/OpenHTJ2K/conformance_data/ds0_ht_02_b11.j2k -o out.ppm -threads 0
[...]
[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] Expected SOP marker
[WARNING] Expected EPH marker
[WARNING] A malformed codeblock that has more than one coding pass, but zero length for 2nd and potential 3rd pass.
==4037690== Invalid read of size 1
==4037690==    at 0x48589FA: opj_t1_ht_decode_cblk (fbc_dec.c:1262)
==4037690==    by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==4037690==    by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==4037690==    by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==4037690==    by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==4037690==    by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==4037690==    by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)
==4037690==    by 0x4881CDA: opj_j2k_decode_tiles (j2k.c:11566)
==4037690==    by 0x487B333: opj_j2k_exec (j2k.c:8903)
==4037690==    by 0x4882AD1: opj_j2k_decode (j2k.c:11912)
==4037690==    by 0x488EF5C: opj_decode (openjpeg.c:494)
==4037690==    by 0x1103AC: main (opj_decompress.c:1547)
==4037690==  Address 0x52884ef is 1 bytes before a block of size 2 alloc'd
==4037690==    at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4037690==    by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4037690==    by 0x48C0676: opj_realloc (opj_malloc.c:244)
==4037690==    by 0x48584E6: opj_t1_ht_decode_cblk (fbc_dec.c:1123)
==4037690==    by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==4037690==    by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==4037690==    by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==4037690==    by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==4037690==    by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==4037690==    by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)
==4037690==    by 0x4881CDA: opj_j2k_decode_tiles (j2k.c:11566)
==4037690==    by 0x487B333: opj_j2k_exec (j2k.c:8903)

So it seems there's an issue with the EPH / SOP markers (or perhaps a more general issue with reading the coding passes that is revealed with the markers), and a potential out-of-bound read when some illegal value is found in a code block.

…d if Mb == 0; that is, when the codeblock has no bitplanes to decode (K_max==0). Also, a bug is fixed whereby the codeblock decoder can write below the last row of the codeblock when the number of rows is odd and larger than 2.
@aous72
Copy link
Contributor Author

aous72 commented Sep 13, 2021

@rouault Thank you Even. @Jamaika1 Thank you.

I hope this fixes the previous issue, the crash. My apologies, it is was a bit something wrong with my code, and a bit of a misunderstanding.

The EPH issue is related to my packet header decoding; I should fix it in the next commit. I need to do some research for it.

Kind regards,
Aous.

Edit: There is potentially another bug I need to work on. In my code, the codeblock decoder can read outside the region of the codeblock bitstream, by up to 8 bytes before or after the bitstream. It is easy to fix, and I will also commit it when I fix the EPH issue.

Edit2: In my work with HTJ2K, I implemented a basic packet header parser that works in cases where the image is directly generated by a tool; I was not after conformance. These files have extra layers that, by themselves, are not needed to decode the bitstream, but they have to be parsed and skipped. Achieving conformance requires some time and some research on my side. I will work on this and come back to you.

rouault and others added 2 commits September 15, 2021 11:59
…ng (#1)

Add dummy parsing of HTJ2K CAP and CPF marker to avoid annoying warning.
@aous72
Copy link
Contributor Author

aous72 commented Sep 15, 2021

@Jamaika1

OpenHTJ2K version 0 no thread C++14
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Stiles={1563,1558} Clevels=3 Corder=CPRL Creversible=Bool
dopen_j2k.exe -i image_21447_24bit-jhc.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 2 has been read.
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped.
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/2
ERROR -> opj_decompress: failed to decode image!

I suspect this is a bug in @osamu620 Osamu-san's code, or in my understanding -- I am assuming it is OpenHTJ2K. I need to discuss this with him. The configuration is also different than the lower files. Stiles={1563,1558} has rows,columns, while I have x,y. This is why you have two tiles instead of 1.
The bug can be summarized as follows:
U_q should be no larger than missing_msbs + 1.

OpenJPH Ver 0.7.3 no thread
htj2k-cjph.exe -i image_21447_24bit.yuv -o image_21447_24bit-jph.j2c -dims {1563,1558} -num_comps 3 -signed false -bit_depth 8 -downsamp {1,1},{1,1},{1,1} -block_size {64,64} -precincts {128,128},{256,256} -prog_order CPRL -reversible true
dopen_j2k.exe -i image_21447_24bit-jph.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.

Error. Codec doesn't create PNG file

As you noticed the color transform is not performed because the original is in YUV.

Grok version 9.4.0 thread=1
htj2k-cgrok.exe -v -i image_21447_24bit.raw -o image_21447_24bit-grok.j2k -H 1 -M 64 -F 1563,1558,3,8,u@1x1:1x1:1x1 -mct 1 -b 64,64 -c [128,128],[256,256] -p CPRL -r 1
dopen_j2k.exe -i image_21447_24bit-grok.j2k -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Generated Outfile xxx.png
decode time: 194 ms

Seems fine to me. Same problem with color transform, I think.

OK Codec creates PNG file
Grok version 9.4.0 EXIF thread=1
htj2k-cgrok.exe -v -i L1004432.tiff -o L1004432.jp2 -H 1 -M 64 -r 1
dopen_j2k.exe -i L1004432.jp2 -o xxx.png

[INFO] Start to read j2k main header (8014).
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Stream reached its end !
color.c:564:color_apply_icc_profile
        channels(3) prec(8) w(5212) h(3468)
        profile: in(0000015799cbd870) out(000001579c5df750)
        render_intent (0)
        color_space: in(0x58595a20)(XYZ )   out:(0x52474220)(RGB )
               type: in(262169)              out:(262169)
[INFO] Generated Outfile xxx.png
decode time: 5926 ms

OK Codec creates PNG file

Proper encoder should keep the color icc profile of the original image.

@osamu620
Copy link

@aous72
Thank you for letting me know. Have you already found any problem in OpenHTJ2K's code?

@Jamaika1
Could you raise an issue OpenHTJ2K repo with the POC files (includes the input image)?

@Jamaika1

OpenHTJ2K version 0 no thread C++14
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Stiles={1563,1558} Clevels=3 Corder=CPRL Creversible=Bool
dopen_j2k.exe -i image_21447_24bit-jhc.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 2 has been read.
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped.
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/2
ERROR -> opj_decompress: failed to decode image!

I suspect this is a bug in @osamu620 Osamu-san's code, or in my understanding -- I am assuming it is OpenHTJ2K. I need to discuss this with him. The configuration is also different than the lower files. Stiles={1563,1558} has rows,columns, while I have x,y. This is why you have two tiles instead of 1.
The bug can be summarized as follows:
U_q should be no larger than missing_msbs + 1.

OpenJPH Ver 0.7.3 no thread
htj2k-cjph.exe -i image_21447_24bit.yuv -o image_21447_24bit-jph.j2c -dims {1563,1558} -num_comps 3 -signed false -bit_depth 8 -downsamp {1,1},{1,1},{1,1} -block_size {64,64} -precincts {128,128},{256,256} -prog_order CPRL -reversible true
dopen_j2k.exe -i image_21447_24bit-jph.j2c -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.

Error. Codec doesn't create PNG file

As you noticed the color transform is not performed because the original is in YUV.

Grok version 9.4.0 thread=1
htj2k-cgrok.exe -v -i image_21447_24bit.raw -o image_21447_24bit-grok.j2k -H 1 -M 64 -F 1563,1558,3,8,u@1x1:1x1:1x1 -mct 1 -b 64,64 -c [128,128],[256,256] -p CPRL -r 1
dopen_j2k.exe -i image_21447_24bit-grok.j2k -o xxx.png

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Generated Outfile xxx.png
decode time: 194 ms

Seems fine to me. Same problem with color transform, I think.

OK Codec creates PNG file
Grok version 9.4.0 EXIF thread=1
htj2k-cgrok.exe -v -i L1004432.tiff -o L1004432.jp2 -H 1 -M 64 -r 1
dopen_j2k.exe -i L1004432.jp2 -o xxx.png

[INFO] Start to read j2k main header (8014).
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
[INFO] Header of tile 1 / 1 has been read.
[INFO] Stream reached its end !
color.c:564:color_apply_icc_profile
        channels(3) prec(8) w(5212) h(3468)
        profile: in(0000015799cbd870) out(000001579c5df750)
        render_intent (0)
        color_space: in(0x58595a20)(XYZ )   out:(0x52474220)(RGB )
               type: in(262169)              out:(262169)
[INFO] Generated Outfile xxx.png
decode time: 5926 ms

OK Codec creates PNG file

Proper encoder should keep the color icc profile of the original image.

@aous72
Copy link
Contributor Author

aous72 commented Sep 15, 2021

@osamu620
My apologies. The code is fine. I think I confused an earlier commit with the latest version of the code, and some other task I was also running in the background.

@aous72
Thank you for letting me know. Have you already found any problem in OpenHTJ2K's code?

@Jamaika1
Copy link
Contributor

@osamu620
Added input file
https://www.sendspace.com/file/3n4kt2

@osamu620
Copy link

osamu620 commented Sep 15, 2021

@osamu620
Added input file
https://www.sendspace.com/file/3n4kt2

Thanks. But here is not a good place to raise an issue. Please bring it to OpenHTJ2K repo If this issue has a relation with OpenHTJ2K library.

…ometime to understand the quantities and what they mean, and therefore I want to leave a version of it for future work. I will simplify the code after this.
@rouault
Copy link
Collaborator

rouault commented Sep 15, 2021

@aous72 you may need to merge the latest upstream master branch into yours to get the fixes for the 2 CI issues that are hopefully now solved with #1380

@Jamaika1
Copy link
Contributor

Jamaika1 commented Sep 19, 2021

test htj2k

ffmpeg.exe -loglevel error -y -i image_21447_24bit.png -pix_fmt yuv444p image_21447_24bit.yuv
ffmpeg.exe -loglevel error -y -i image_21447_24bit.png -pix_fmt yuv444p image_21447_24bit.ppm
ffmpeg.exe -loglevel error -y -i image_21447_24bit.png -f rawvideo -pix_fmt yuv444p image_21447_24bit.raw

htj2k-cgrok.exe -v -i image_21447_24bit.raw -o image_21447_24bit-grok.j2k -H 1 -M 64 -F 1563,1558,3,8,u@1x1:1x1:1x1 -mct 1 -b 64,64 -c [128,128],[256,256] -p CPRL -r 1
htj2k-cjph.exe -i image_21447_24bit.yuv -o image_21447_24bit-jph.j2c -dims {1563,1558} -num_comps 3 -signed false -bit_depth 8 -downsamp {1,1},{1,1},{1,1} -block_size {64,64} -precincts {128,128},{256,256} -prog_order CPRL -reversible true
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Stiles={1563,1558} Clevels=3 Corder=CPRL Creversible=Bool -num_threads 1
htj2k-dgrok.exe -v -i image_21447_24bit-grok.j2k -o xxx1a.raw -H 1
htj2k-dgrok.exe -v -i image_21447_24bit-jph.j2c -o xxx1b.raw -H 1
htj2k-dgrok.exe -v -i image_21447_24bit-jhc.j2c -o xxx1c.ppm -H 1
htj2k-djph.exe -i image_21447_24bit-grok.j2k -o xxx2a.raw
htj2k-djph.exe -i image_21447_24bit-jph.j2c -o xxx2b.raw
htj2k-djph.exe -i image_21447_24bit-jhc.j2c -o xxx2c.ppm
htj2k-djhc.exe -i image_21447_24bit-grok.j2k -o xxx3a.raw -num_threads 1
htj2k-djhc.exe -i image_21447_24bit-jph.j2c -o xxx3b.raw -num_threads 1
htj2k-djhc.exe -i image_21447_24bit-jhc.j2c -o xxx3c.ppm -num_threads 1
dopen_j2k.exe -i image_21447_24bit-grok.j2k -o xxx4a.raw
dopen_j2k.exe -i image_21447_24bit-jph.j2c -o xxx4b.raw
dopen_j2k.exe -i image_21447_24bit-jhc.j2c -o xxx4c.ppm

htj2k-dgrok.exe -v -i image_21447_24bit-jhc.j2c -o xxx1c.ppm -H 1
[2021-09-19 08:52:22.548] [error] Error in HT block coder
[2021-09-19 08:52:22.548] [error] Failed to decompress tile 0/2
htj2k-djph.exe -i image_21447_24bit-grok.j2k -o xxx2a.raw
ojph error 0x20000006 at ojph_expand.cpp:295: unknown output file extension; only (pgm, ppm, tif and yuv) are supported
htj2k-djph.exe -i image_21447_24bit-jph.j2c -o xxx2b.raw
ojph error 0x20000006 at ojph_expand.cpp:295: unknown output file extension; only (pgm, ppm, tif and yuv) are supported
htj2k-djph.exe -i image_21447_24bit-jhc.j2c -o xxx2c.ppm
ojph error 0x000300A1 at ojph_codestream.cpp:4077: Error decoding a codeblock
htj2k-djhc.exe -i image_21447_24bit-grok.j2k -o xxx3a.raw -num_threads 1
Error. Incomplete picture
htj2k-djhc.exe -i image_21447_24bit-jph.j2c -o xxx3b.raw -num_threads 1
Error. Incomplete picture
dopen_j2k.exe -i image_21447_24bit-grok.j2k -o xxx4a.raw
dopen_j2k.exe -i image_21447_24bit-jph.j2c -o xxx4b.raw
dopen_j2k.exe -i image_21447_24bit-jhc.j2c -o xxx4c.ppm
OpenJPEG works correctly
Thanks for developing openjpeg 8bit SDR :)
htj2k-dgrok.exe -v -i image_21447_30bit-jph.j2c -o yyy1b.raw -H 1
Wrong raw file size 10bit.
htj2k-djph.exe -i image_21447_30bit-jph.j2c -o yyy2b.raw
ojph error 0x20000006 at ojph_expand.cpp:295: unknown output file extension; only (pgm, ppm, tif and yuv) are supported
htj2k-djhc.exe -i image_21447_30bit-jph.j2c -o yyy3b.raw -num_threads 1
Wrong raw file size 10bit. Creates three raw files
dopen_j2k.exe -i image_21447_30bit-jph.j2c -o xxx4b.raw

@rouault
Copy link
Collaborator

rouault commented Sep 20, 2021

Hi @aous72 . Did you have a chance to make some progress on the conformance test files ?
Regarding the crash in multithreaded mode, it seems commit aous72@4ebb7d2 was its resolution , right ?

@aous72
Copy link
Contributor Author

aous72 commented Sep 20, 2021

Hi @rouault. For conformance, no progress yet; this is the next step.
Commit aous72/openjpeg@4ebb7d2 fixed that issue; it was writing outside the available buffer. It was a bug in that code that protect against this.
Since then I modified the block decoder messaging, and added support for vertically causal mode. I will commit that today, together with some modifications to make sure that I do not read outside of the codeblock data buffer.

…oding in HT mode. 2. HT block decoder should not read from outside a codeblock lenght -- this required modification of data reading algorithm, which improved them. 3. Improve messaging around unreasonable or illegal conditions that may occur during block decoding; two of these conditions are better moved to t2.c.
@rouault
Copy link
Collaborator

rouault commented Sep 23, 2021

How do you think we should ago about this task

So this would be an overhaul of opj_t2_read_packet_header() ? I thought that HT only impacted codeblock decoding, not packet header. But I've obviously not dug into the specification too deep.
To which missing documentation you refer too ? If this is about openjpeg code, there's no hidden extra documentation AFAIK. Everything is in the code, and the rest is implied by the J2K specification.
As far as rewriting this parser, I don't have specific advice because I don't really see the implication nor who wants to commit to that effort and to which proportion.
I've submitted aous72#2 to fix the out-of-bounds read I noted on a conformance test file (and other conformance test files also succeed or fail 'cleanly')
So we're probably good enough to merge as it, and next improvements can be dealt as follow-up pull requests

Hum, but trying a bit ossfuzz (https://github.com/google/oss-fuzz), on that branch, I see we have other out-of-bounds reads.
How to reproduce:
initial setup:

git clone https://github.com/rouault/oss-fuzz
cd oss-fuzz
git checkout openjpeg_test_htj2k

Each time a change is one in the build recipee (at https://github.com/rouault/oss-fuzz/blob/openjpeg_test_htj2k/projects/openjpeg/Dockerfile ) or in the git branches pointed to it:

# to clean a previously oss-fuzz image: docker rmi gcr.io/oss-fuzz/openjpeg
python infra/helper.py build_fuzzers --architecture x86_64 --sanitizer address openjpeg
python infra/helper.py run_fuzzer openjpeg opj_decompress_fuzzer

It outputs

==13==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6120000200dc at pc 0x00000069d69e bp 0x7ffe7b5a7cd0 sp 0x7ffe7b5a7cc8
WRITE of size 4 at 0x6120000200dc thread T0
SCARINESS: 46 (4-byte-write-heap-buffer-overflow-far-from-bounds)
    #0 0x69d69d in opj_t1_ht_decode_cblk /src/openjpeg/src/lib/openjp2/fbc_dec.c:1682:24
    #1 0x624aeb in opj_t1_clbl_decode_processor /src/openjpeg/src/lib/openjp2/t1.c:1690:26
    #2 0x5f5b9f in opj_thread_pool_submit_job /src/openjpeg/src/lib/openjp2/thread.c:835:9
    #3 0x6239f1 in opj_t1_decode_cblks /src/openjpeg/src/lib/openjp2/t1.c:1943:21
    #4 0x5e2c76 in opj_tcd_t1_decode /src/openjpeg/src/lib/openjp2/tcd.c:2000:9
    #5 0x5e2c76 in opj_tcd_decode_tile /src/openjpeg/src/lib/openjp2/tcd.c:1654:11
    #6 0x57c4e2 in opj_j2k_decode_tile /src/openjpeg/src/lib/openjp2/j2k.c:9841:11
    #7 0x59e741 in opj_j2k_decode_tiles /src/openjpeg/src/lib/openjp2/j2k.c:11683:15
    #8 0x582dd7 in opj_j2k_exec /src/openjpeg/src/lib/openjp2/j2k.c:8985:33
    #9 0x582dd7 in opj_j2k_decode /src/openjpeg/src/lib/openjp2/j2k.c:11986:11
    #10 0x55e187 in LLVMFuzzerTestOneInput /src/openjpeg/./tests/fuzzers/opj_decompress_fuzzer.cpp:199:13
    #11 0x456b73 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp
    #12 0x45636a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) cxa_noexception.cpp
    #13 0x457bdb in fuzzer::Fuzzer::MutateAndTestOne() cxa_noexception.cpp
    #14 0x458695 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile> >&) cxa_noexception.cpp
    #15 0x447e30 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp
    #16 0x470ec2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #17 0x7f6bb88440b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #18 0x41f6dd in _start (/out/opj_decompress_fuzzer+0x41f6dd)

and the reproducer is in
crash-0ca488d7b3a37b5c43b61005ea937250457d41f8.zip

@osamu620
Copy link

Hi Even,

I spent most of the last two days trying to achieve conformance.
I know the code in the committed form passes HT profile 1, and maybe 1 or 2 tests of HT profile 0.

The task is bigger than I thought it would be, and I suspect it requires a major overhaul of the packet header parser, and possibly the codeblock structure. I tried to borrow @osamu620 packet header parser in OpenHTJ2K (released under BSD-3), but he employs different representation (I have not commit this, because it is a mess); in particular, OpenJPEG stores segments, which may contain multiple coding passes, while OpenHTJ2K stores coding passes.

I would be happy to write the parser myself, but I cannot find proper documentations for it, and code does not replace good description.

How do you think we should ago about this task. @osamu620 might be willing to help? or, keep it the way it is now?

Thank you.

Kind regards,
Aous.

@aous72
I would be happy to help to discuss this topic.

rouault and others added 2 commits September 24, 2021 16:53
#2)

Avoids the following issue:

$ valgrind bin/opj_decompress -i ~/OpenHTJ2K/conformance_data/ds0_ht_02_b11.j2k -o out.ppm -threads 0

==4037690== Invalid read of size 1
==4037690==    at 0x48589FA: opj_t1_ht_decode_cblk (fbc_dec.c:1262)
==4037690==    by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==4037690==    by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==4037690==    by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==4037690==    by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==4037690==    by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==4037690==    by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)
==4037690==    by 0x4881CDA: opj_j2k_decode_tiles (j2k.c:11566)
==4037690==    by 0x487B333: opj_j2k_exec (j2k.c:8903)
==4037690==    by 0x4882AD1: opj_j2k_decode (j2k.c:11912)
==4037690==    by 0x488EF5C: opj_decode (openjpeg.c:494)
==4037690==    by 0x1103AC: main (opj_decompress.c:1547)
==4037690==  Address 0x52884ef is 1 bytes before a block of size 2 alloc'd
==4037690==    at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4037690==    by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4037690==    by 0x48C0676: opj_realloc (opj_malloc.c:244)
==4037690==    by 0x48584E6: opj_t1_ht_decode_cblk (fbc_dec.c:1123)
==4037690==    by 0x48B28E5: opj_t1_clbl_decode_processor (t1.c:1690)
==4037690==    by 0x4854A33: opj_thread_pool_submit_job (thread.c:835)
==4037690==    by 0x48B37C3: opj_t1_decode_cblks (t1.c:1943)
==4037690==    by 0x48BD668: opj_tcd_t1_decode (tcd.c:2000)
==4037690==    by 0x48BCADF: opj_tcd_decode_tile (tcd.c:1654)
==4037690==    by 0x487D348: opj_j2k_decode_tile (j2k.c:9759)
==4037690==    by 0x4881CDA: opj_j2k_decode_tiles (j2k.c:11566)
==4037690==    by 0x487B333: opj_j2k_exec (j2k.c:8903)

I've also simplified a bit the allocation of the concatenated code block
buffer, to remove the OPJ_COMMON_CBLK_DATA_EXTRA that I believe is a trick only
needed for regular code block decoding, not HT.
…uzzing, whereby s decoded vlc codeword indicates a significant sample outside of a codeblock.
@aous72
Copy link
Contributor Author

aous72 commented Sep 24, 2021

@osamu620 Thank you Osamu for the offer. I will write to you privately, unless you want my question to be like a blog for other people to have a look at. In this case, I can put them in an issue on OpenHTJ2K.

Hi Even,

Thank you for the fuzz test.

I merged your pull request and modified it a bit to do one more check.
I also discovered why the fuzz was failing and fixed it. After that, one fuzzer run crashed with the info included below, but the next one run for like 90000 iterations without issues.
I am not familiar with these tools; in the end, I figured out that I can commit my changes, and then pull let the fuzzer pull them. I am also not sure how to replay the output file.

During the fuzzing, there was an out of memory failure, but it was not in my code. The report is

==13== ERROR: libFuzzer: out-of-memory (used: 4169Mb; limit: 2560Mb)
   To change the out-of-memory limit use -rss_limit_mb=<N>

Live Heap Allocations: 18599345359 bytes in 81300 chunks; quarantined: 8108254 bytes in 4237 chunks; 126904 other chunks; total chunks: 212441; showing top 95% (at most 8 unique contexts)
18119671920 byte(s) (97%) in 65282 allocation(s)
    #0 0x5252f2 in __interceptor_calloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:138:3
    #1 0x596622 in opj_j2k_read_siz /src/openjpeg/src/lib/openjp2/j2k.c:2478:53
    #2 0x58e3b5 in opj_j2k_read_header_procedure /src/openjpeg/src/lib/openjp2/j2k.c:8903:14
    #3 0x576dc0 in opj_j2k_exec /src/openjpeg/src/lib/openjp2/j2k.c:8985:33
    #4 0x576dc0 in opj_j2k_read_header /src/openjpeg/src/lib/openjp2/j2k.c:8407:11
    #5 0x55dfff in LLVMFuzzerTestOneInput /src/openjpeg/./tests/fuzzers/opj_decompress_fuzzer.cpp:146:10
    #6 0x456b73 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp
    #7 0x45636a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) cxa_noexception.cpp
    #8 0x457bdb in fuzzer::Fuzzer::MutateAndTestOne() cxa_noexception.cpp
    #9 0x458695 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile> >&) cxa_noexception.cpp
    #10 0x447e30 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp
    #11 0x470ec2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #12 0x7f8060d4e0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

DEDUP_TOKEN: __interceptor_calloc--opj_j2k_read_siz--opj_j2k_read_header_procedure
MS: 1 PersAutoDict- DE: "\xff\x02"-; base unit: f3477a9f6df2233bdac37738996d8858bbc47423
artifact_prefix='./'; Test unit written to ./oom-c2acb1ad04a5a9e484624ec94f05668e26554a21
SUMMARY: libFuzzer: out-of-memory

and the file is
oom-c2acb1ad04a5a9e484624ec94f05668e26554a21.zip
It might be normal operation.

Thank you.

Kind regards,
Aous.

@rouault
Copy link
Collaborator

rouault commented Sep 24, 2021

During the fuzzing, there was an out of memory failure, but it was not in my code. The report is

This is indeed unrelated to your changes and already happens with openjpeg master. As openjpeg instantiates a data structure for each tile, and for the "current" decoded tile, it also instanciates all tile components, bands, precincts and codeblocks data structures, that can lead to huge allocations on big images. ossfuzz runs processes with a 2 GB heap limit, and crashes when it is reached. I guess a more clever design of openjpeg could probably most of those allocations, but that seems like a huge effort, and is out of scope of this PR

@rouault
Copy link
Collaborator

rouault commented Sep 24, 2021

I'm happy with the PR as it, and will merge it soon. I'm preparing adding a few test cases to add to the test suite.

Has anyone seen a JP2 file with HTJ2K ? or know how to generate one

@rouault
Copy link
Collaborator

rouault commented Sep 24, 2021

What does fbc in fbc_dec.c means by the way ? May be rename it as htj2k_dec.c ?

@rouault
Copy link
Collaborator

rouault commented Sep 24, 2021

I've run a performance test with that branch, on a 8192x8192 3-channel 8-bit image, lossless conversion, with 1024x1024 tiles.
compressed with opj_compress for regular J2K and ojph_compress for HTJ2K
regular J2K file size: 11 488 793 bytes
HTJ2K file size: 12 870 702 bytes

$ time bin/opj_decompress -i /tmp/extract_regular.j2k  -o /tmp/tmp.tif -threads 0  >/dev/null
real	0m2,082s
user	0m1,969s
sys	0m0,085s

$ time bin/opj_decompress -i /tmp/extract_htj2k.j2k   -o /tmp/tmp.tif -threads 0  >/dev/null
real	0m0,890s
user	0m0,755s
sys	0m0,118s

so a nice improvement but still far from the 30x promise :-)

@aous72
Copy link
Contributor Author

aous72 commented Sep 24, 2021

Hi Even,

Thank you for running performance tests.

I'm happy with the PR as it, and will merge it soon. I'm preparing adding a few test cases to add to the test suite.

Excellent.

Has anyone seen a JP2 file with HTJ2K ? or know how to generate one

The latest demo version of Kakadu from kakadusoftware.com can generate them. There is also my code, OpenJPH, Osamu's version OpenHTJ2K, and Aaron's version in Grok.

What does fbc in fbc_dec.c means by the way ? May be rename it as htj2k_dec.c ?

Feel free to rename it. It stands for fast block coder. You can call it htj2k_dec.c or even ht_dec.c, which is easier on the tongue.

so a nice improvement but still far from the 30x promise :-)

To get there, you need a lot optimization. The speed improvement comes from:

  1. HT accesses a sample one or two times only, while, in Part 1, so many accesses are needed decoding the multiple passes. We are getting this.
  2. HT can be optimized using SIMD instructions, which is not possible with Part 1. So you can potentially do something like 16 samples in one instruction. Of course we are not doing that.
  3. On an unrelated point, for hardware implementations, some of the decoding steps can be done in parallel, or with little delay; for example decoding magsgn segment can start after decoding one or two VLC codes. Also, decoding of MagRef/SigProp can start after decoding 4/6 rows of the cleanup pass.

Performance is usually held back by the slowest part of the chain. I do not know what that is. You can try without any wavelet decompositions, so the wavelet transform is taken out.

Thanks a lot.

Kind regards,
Aous.

@aous72
Copy link
Contributor Author

aous72 commented Sep 24, 2021

By the way, I put the license and copyright there, but this should not be an issue; feel free to change it.

@rouault
Copy link
Collaborator

rouault commented Sep 24, 2021

Has anyone seen a JP2 file with HTJ2K ? or know how to generate one

I meant a .jp2 file with JP2 boxes, not a raw JPEG2000 codestream, which I don't think openjph and openhtj2k can generate. Perhaps grok / kakadu indeed.

Thanks for your thoughts on potential perf improvements.

@Jamaika1
Copy link
Contributor

Quick test htjp2 EXIF

htj2k-cgrok.exe -v -i L1004432.tiff -o image_21447_24bit-grok.jp2 -H 1 -M 64 -r 1

htj2k-dgrok.exe -v -i image_21447_24bit-grok.jp2 -o xxx1a.png -H 1
Error: No create PNG.
htj2k-dgrok.exe -v -i image_21447_24bit-grok.jp2 -o xxx1a.tiff -H 1
Error: No create TIFF
htj2k-djph.exe -i image_21447_24bit-grok.jp2 -o xxx1b.tif
OK. No EXIF
htj2k-djhc.exe -i image_21447_24bit-grok.jphc -o xxx1c.ppm -num_threads 1
Assertion failed: word == _SOC, file j2kmarkers.cpp, line 1594
dopen_j2k.exe -i image_21447_24bit-grok.jp2 -o xxx1d.png
OK.
dopen_j2k.exe -i image_21447_24bit-grok.jp2 -o xxx1d.tiff
OK. No EXIF

@rouault
Copy link
Collaborator

rouault commented Sep 25, 2021

Superseded per #1381 that adds renaming of fbc_dec.c to ht_dec.c, adds a few test cases and squash the commits

@Jamaika1
Copy link
Contributor

Jamaika1 commented May 21, 2022

Testing decompression of new codecs HTJ2K

Testing GROK
Grok version 9.7.6-3a04a36 (OpenHTJ2K 0.0.0-0b138aa or OpenJPH 0.8.3-1c56214)
OpenHTJ2K 0.0.0-0b138aa
OpenJPH 0.8.3-1c56214
OpenJPEG 2.5.0-5292728

htj2k-cgrok_ojph.exe -v -i image_21447_24bit.png -o image_21447_24bit-grokjph.j2k -H 1 -M 64 -r 1
Codec creates image.
htj2k-cgrok_ojhc.exe -v -i image_21447_24bit.png -o image_21447_24bit-grokjhc.j2k -H 1 -M 64 -r 1
Codec creates image.

htj2k-dgrok_ojph.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -H 1
Critical error
htj2k-dgrok_ojhc.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -H 1
Critical error

htj2k-dgrok_ojph.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -H 1
[2022-05-21 17:37:04.399] [error] Error in HT block coder
[2022-05-21 17:37:04.400] [error] Failed to decompress tile 0/1
htj2k-dgrok_ojhc.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -H 1
Critical error

htj2k-djhc.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -num_threads 1
decompress {no num_threads function visible in help)
htj2k-djph.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjph.ppm
ojph error 0x000300A1 at ojph_codestream.cpp:4071: Error decoding a codeblock

htj2k-djph.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm
decompress
htj2k-djhc.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -num_threads 1
WARNING: number of passes 1 exceeds number of empty passes 3
decompress {incorrect data, no num_threads function visible in help)

dopenhtj2k.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm
decompress
dopenhtj2k.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped. U_q islarger than bitplanes + 1
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/1

Testing OpenJPH
htj2k-cjph.exe -i image_21447_24bit.ppm -o image_21447_24bit-jph.j2c -reversible true
Codec creates image.

htj2k-djph.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-grokjph.ppm
decompress

htj2k-djhc.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-grokjph.ppm -num_threads 1
decompress {no num_threads function visible in help)

Testing OpenHTJ2K
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Creversible=Bool -num_threads 1

htj2k-djhc.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-grokjhc.ppm -num_threads 1
decompress {incorrect data, no num_threads function visible in help)

htj2k-djph.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-grokjhc.ppm
ojph error 0x000300A1 at ojph_codestream.cpp:4071: Error decoding a codeblock

dopenhtj2k.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-grokjph.ppm
decompress
dopenhtj2k.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-grokjhc.ppm
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped. U_q islarger than bitplanes + 1
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/1

@aous72
Copy link
Contributor Author

aous72 commented May 22, 2022

@Jamaika1
Hi Lucas,

Thank you for putting this in.

  1. Could you please provide a link to image_21447_24bit.png. The link above is not working.
  2. Are you using the latest available versions?
  3. For these errors,
htj2k-cgrok_ojph.exe -v -i image_21447_24bit.png -o image_21447_24bit-grokjph.j2k -H 1 -M 64 -r 1
Codec creates image.
htj2k-cgrok_ojhc.exe -v -i image_21447_24bit.png -o image_21447_24bit-grokjhc.j2k -H 1 -M 64 -r 1
Codec creates image.

htj2k-dgrok_ojph.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -H 1
Critical error
htj2k-dgrok_ojhc.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -H 1
Critical error

htj2k-dgrok_ojph.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -H 1
[2022-05-21 17:37:04.399] [error] Error in HT block coder
[2022-05-21 17:37:04.400] [error] Failed to decompress tile 0/1
htj2k-dgrok_ojhc.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -H 1
Critical error

htj2k-djhc.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm -num_threads 1
decompress {no num_threads function visible in help)
htj2k-djph.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjph.ppm
ojph error 0x000300A1 at ojph_codestream.cpp:4071: Error decoding a codeblock

htj2k-djph.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm
decompress
htj2k-djhc.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -num_threads 1
WARNING: number of passes 1 exceeds number of empty passes 3
decompress {incorrect data, no num_threads function visible in help)

dopenhtj2k.exe -i image_21447_24bit-grokjph.j2k -o image_21447_24bit-grokjph.ppm
decompress
dopenhtj2k.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm
[ERROR] Malformed HT codeblock. Decoding this codeblock is stopped. U_q islarger than bitplanes + 1
[ERROR] Failed to decode.
[ERROR] Failed to decode tile 1/1

Assuming you did things correctly, @boxerab needs to look at these, as his code does not seem to decode what it creates.

  1. The last time I checked, openjpeg does not an issue with The message "U_q is larger than bitplanes + 1." My OpenJPH code has a problem with this, which I fixed. U_q cannot be larger than missing_msbs + 2.
  2. Is Creversible=Bool corect in htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Creversible=Bool -num_threads 1?

Cheers,
Aous.

@Jamaika1
Copy link
Contributor

Jamaika1 commented May 22, 2022

Hi Aous72,

I didn't think about the choice of the photo. The first is better.
My thoughts.
I could have made mistakes adjusting grok to the new codec versions but why is openhtj2k not working?
My codecs don't have SIMD functionality.

Do not use thread higher than one. Codecs don't work under Windows 64bit even with the latest grok patches.
https://www.sendspace.com/file/we1hry

My omissions
Codecs OpenJPH and OpenHTJ2K should be STATIC.

htj2k-cgrok_ojhc.exe -v -i image_21447_24bit.png -o image_21447_24bit-grokjhc.j2k -H 1 -M 64 -r 1
htj2k-djhc.exe -i image_21447_24bit-grokjhc.j2k -o image_21447_24bit-grokjhc.ppm -num_threads 1
https://iili.io/XqNZy7.md.png

@aous72
Copy link
Contributor Author

aous72 commented May 26, 2022

Hi Lucas,

I ran these tests in this order

OpenHTJ2K/build/bin/open_htj2k_enc -i image_21447_24bit.ppm -o test.j2c Creversible=yes

OpenJPH/bin/ojph_expand -i test.j2c -o test.ppm
No problem

openjpeg/build/bin/opj_decompress -i test.j2c -o test.ppm
no problem

Then these

OpenJPH/bin/ojph_compress -reversible true -o test.j2c -i ../tests/image_21447_24bit.ppm 

OpenHTJ2K/build/bin/open_htj2k_dec -i test.j2c -o test.ppm
No problem

openjpeg/build/bin/opj_decompress -i test.j2c -o test.ppm
No problem

Get the latest versions of the code. Do NOT modify, and test.

Cheers,
Aous

@aous72
Copy link
Contributor Author

aous72 commented May 26, 2022

@Jamaika1

These are the tests I ran.

OpenHTJ2K/build/bin/open_htj2k_enc -i image_21447_24bit.ppm -o test.j2c Creversible=yes

OpenHTJ2K/build/bin/open_htj2k_dec -i test.j2c -o test.ppm
No problem

ojph_expand -i test.j2c -o test.ppm
No problem

openjpeg/build/bin/opj_decompress -i test.j2c -o test.ppm
No problem

Then

ojph_compress -reversible true -o test.j2c -i image_21447_24bit.ppm

ojph_expand -i test.j2c -o test.ppm
No problem

OpenHTJ2K/build/bin/open_htj2k_dec -i test.j2c -o test.ppm
No problem

openjpeg/build/bin/opj_decompress -i test.j2c -o test.ppm
No problem

Get latest code. Do NOT modify, and test.

Cheers,
Aous

@Jamaika1
Copy link
Contributor

Jamaika1 commented May 26, 2022

For me the results aren't satisfactory for Windows 10.
OpenJPH v0.9.0-be64108
OpenHTJ2K v0.0.0-5265cc6

htj2k-cjph.exe -i image_21447_24bit.ppm -o image_21447_24bit-jph.j2c -reversible true
htj2k-cjhc.exe -i image_21447_24bit.ppm -o image_21447_24bit-jhc.j2c Creversible=Bool -num_threads 1

htj2k-djhc.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-jph_hc.ppm -num_threads 1
htj2k-djhc.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-jhc_hc.ppm -num_threads 1
htj2k-djph.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-jph_ph.ppm
htj2k-djph.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-jhc_ph.ppm
dopenhtj2k.exe -i image_21447_24bit-jph.j2c -o image_21447_24bit-jph_oj.ppm
dopenhtj2k.exe -i image_21447_24bit-jhc.j2c -o image_21447_24bit-jhc_oj.ppm

How to decode grok and openjpeg photos with the latest versions? A separate topic.
What define did you add for HTJ2K?
https://www.sendspace.com/file/ny7822

@aous72
Copy link
Contributor Author

aous72 commented May 26, 2022

  1. This is wrong => "Creversible=Bool". Must be "Creversible=yes".
  2. openjpeg generates JPEG2000 part 1 only. OpenJPH cannot decode these.
  3. I do not know about grok. Ask the author.

OpenJPH only creates and decodes Part 15. Also called HTJ2K.
openjpeg creates Part 1, and decode Parts 1 and 15.
OpenHTJ2K I don't know. I think can create and decode parts 1 and 15.
Grok I don't know.

Aous.

@Jamaika1
Copy link
Contributor

Jamaika1 commented May 26, 2022

  1. This is wrong => "Creversible=Bool". Must be "Creversible=yes".
  2. openjpeg generates JPEG2000 part 1 only. OpenJPH cannot decode these.
  3. I do not know about grok. Ask the author.

OpenJPH only creates and decodes Part 15. Also called HTJ2K. openjpeg creates Part 1, and decode Parts 1 and 15. OpenHTJ2K I don't know. I think can create and decode parts 1 and 15. Grok I don't know.

Aous.

Creversible=Bool:
  yes for lossless mode, no for lossy mode.

In that case the descriptions are wrong in help. There is no improvement.

hmm...

A month ago I added the original ojph_block_decoder.cpp and ojph_block_encoder.cpp files to grok_jph. The codec worked. Currently, we can dream about decoding.

OpenJPH decodes OpenHTJ2k. Success. :)
Jamaika

@Jamaika1
Copy link
Contributor

Question to the experts.
Is this file correct?
https://www.sendspace.com/file/k86gt4

@aous72
Copy link
Contributor Author

aous72 commented May 26, 2022

It is corrupt (or incorrect) in a few codeblocks.

The following command ignores incorrect codeblocks
ojph_expand -i image_21447_24bit-grokjhc.j2k -o test.ppm -resilient true

The best tool we have, and it is a reference for me, is available here. Kakadu

@osamu620
Copy link

  1. This is wrong => "Creversible=Bool". Must be "Creversible=yes".
  2. openjpeg generates JPEG2000 part 1 only. OpenJPH cannot decode these.
  3. I do not know about grok. Ask the author.

OpenJPH only creates and decodes Part 15. Also called HTJ2K. openjpeg creates Part 1, and decode Parts 1 and 15. OpenHTJ2K I don't know. I think can create and decode parts 1 and 15. Grok I don't know.
Aous.

Creversible=Bool:
  yes for lossless mode, no for lossy mode.

In that case the descriptions are wrong in help. There is no improvement.

hmm...

A month ago I added the original ojph_block_decoder.cpp and ojph_block_encoder.cpp files to grok_jph. The codec worked. Currently, we can dream about decoding.

OpenJPH decodes OpenHTJ2k. Success. :) Jamaika

OpenHTJ2K currently creates only Part 15 codestreams. It can decode both Part 1 and Part 15. I agree the help message in OpenHTJ2K should be improved.

@aous72
Copy link
Contributor Author

aous72 commented May 26, 2022

@osamu620
Thank you Osamu.
I think the encoder should complain if you provide something that does not make sense; when I tried "Creversible=Bool", there was no complain.

Cheers,
Aous.

@osamu620
Copy link

@osamu620 Thank you Osamu. I think the encoder should complain if you provide something that does not make sense; when I tried "Creversible=Bool", there was no complain.

Cheers, Aous.

@aous72
Yes. You are right, and I will make the encoder app do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants