libjpeg-turbo / libjpeg-turbo

Main libjpeg-turbo repository
https://libjpeg-turbo.org
Other
3.79k stars 1.03k forks source link

TurboJPEG API: Support 4:1:0 and 2:4 (rotated 4:1:0) subsampling #436

Open jfolz opened 4 years ago

jfolz commented 4 years ago

Have you searched the existing issues (both open and closed) in the libjpeg-turbo issue tracker to ensure that this bug report is not a duplicate? There is a similar issue #323 (also by me), but the subsampling types it fails on are different.

Does this bug report describe one of the two known and unsolvable issues with the JPEG format? No

Clear and concise description of the bug: I found some more unusual images that decompress correctly with djpeg, but tjDecompressHeader3 reports "Could not determine subsampling type for JPEG image".

Steps to reproduce the bug (using only libjpeg-turbo): Run tjDecompressHeader3 with one of the example images.

Image(s) needed in order to reproduce the bug (if applicable): Example 1 with djpeg -verbose output of:

Start of Image
JFIF APP0 marker: version 1.01, density 72x72  1
Miscellaneous marker 0xe1, length 12460
Define Quantization Table 0  precision 0
Define Quantization Table 1  precision 0
Start Of Frame 0xc0: width=1340, height=1207, components=3
    Component 1: 4hx1v q=0
    Component 2: 2hx1v q=1
    Component 3: 2hx1v q=1
Define Huffman Table 0x00
Define Huffman Table 0x10
Define Huffman Table 0x01
Define Huffman Table 0x11
Start Of Scan: 3 components
    Component 1: dc=0 ac=0
    Component 2: dc=1 ac=1
    Component 3: dc=1 ac=1
  Ss=0, Se=63, Ah=0, Al=0
End Of Image

Example 2 with djpeg -verbose output of:

Start of Image
JFIF APP0 marker: version 1.01, density 72x72  1
Define Quantization Table 0  precision 0
Define Quantization Table 1  precision 0
Start Of Frame 0xc0: width=530, height=458, components=3
    Component 1: 4hx2v q=0
    Component 2: 1hx1v q=1
    Component 3: 1hx1v q=1
Define Huffman Table 0x00
Define Huffman Table 0x10
Define Huffman Table 0x01
Define Huffman Table 0x11
Start Of Scan: 3 components
    Component 1: dc=0 ac=0
    Component 2: dc=1 ac=1
    Component 3: dc=1 ac=1
  Ss=0, Se=63, Ah=0, Al=0
End Of Image

Expected behavior: tjDecompressHeader3 identifies subsampling type correctly.

Observed behavior: tjDecompressHeader3 is not able to determine subsampling type and decoding has to be stopped.

Platform(s) (compiler version, operating system version, CPU) on which the bug was observed: Probably irrelevant, but: GCC 7.5.0, OpenSuse Leap 15.1 (kernel 4.12.14), Intel(R) Core(TM) i7-5930K.

libjpeg-turbo release(s), commit(s), or branch(es) in which the bug was observed (always test the tip of the master branch or the latest stable pre-release to verify that the bug hasn't already been fixed): v 2.0.4.

If the bug is a regression, the specific commit that introduced the regression (use git bisect to determine this): AFAIK this has never worked.

Additional information: None

dcommander commented 4 years ago

The TurboJPEG API handles common chroma subsampling configurations, but it cannot handle every possible combination of horizontal and vertical sampling factors.

The second image appears to use "4:1:0" (AKA "4:2") subsampling, which is a known (albeit rare) form of 8x chroma subsampling. That image could be accommodated by introducing a new subsampling option (TJSAMP_410) into the TurboJPEG API. That would be straightforward but labor-intensive, since it would require extending all of the API functions (including the YUV functions) that deal with subsampling, as well as extending TJUnitTest and TJBench to test the new subsampling configuration.

The first image doesn't appear to use any known subsampling configuration. Thus, the first image could not be accommodated without extensive modifications to the TurboJPEG API-- extending it to handle arbitrary subsampling configurations.

In both cases, the modifications would represent an enhancement rather than a bug fix, and I have no funding available for such a project right now. If your organization wishes to sponsor this feature, then I would be happy to provide you with a cost estimate offline. Otherwise, it's not likely to happen anytime soon.

jfolz commented 4 years ago

Thank you for the detailed analysis. I will ponder my options for a bit, but as you said these are very rare. I found less than 20 of the 4:1:0 kind and just a couple of the really weird one in over a million images. Supporting these kinds of images is probably not worth it if that requires massive changes to the library.

dcommander commented 4 years ago

Supporting 4:1:0 would be a non-disruptive and backward-compatible change-- probably a day's work or in that neighborhood. Thus, supporting that subsampling configuration would make a lot more sense than supporting arbitrary subsampling configurations. The latter would require a wholesale rewrite of almost the entire TurboJPEG API.

dcommander commented 4 years ago

Note that the wholesale rewrite I propose here would subsume this enhancement, but per above, it would be much easier to just add a TJSAMP_410 constant to the existing TurboJPEG API.

dcommander commented 3 years ago

Subsumed by #517

dcommander commented 1 year ago

This is implemented in the TurboJPEG 3 API overhaul, using several new mechanisms:

dcommander commented 1 year ago

https://github.com/libjpeg-turbo/libjpeg-turbo/commit/fc881ebb211b2ba6292d35691a946e1f9c1374b4 adds explicit support for 4:4:1 (transposed 4:1:1) subsampling, in order to fully support lossless transformation chains that begin by rotating or transposing a 4:1:1 JPEG image. (Refer to #659.) That gives the TurboJPEG 3 API full coverage of all 1X, 2X, and 4X chrominance subsampling levels.

Explicitly supporting the two named 8X subsampling levels (4:1:0 and 4:2:1) would be a trivial enhancement, if anyone cares enough about those types of images to want to partially decompress them, losslessly crop them, or decompress them to planar YUV images. Personally, I don't, but I would happily accept funding to implement those subsampling types.

dcommander commented 2 months ago

Reopening this feature request, since arbitrary subsampling factors didn't land in the TurboJPEG v3 API and I have no idea when or if the TurboJPEG v4 API (#646) will land. For now, I'm focusing on incrementally extending the TurboJPEG v3 API to cover as much of the libjpeg API functionality as possible without completely overhauling it. Supporting 4:1:0 and 2:4 subsampling in the existing API would be very straightforward and would extend coverage to almost all JPEG images "in the wild." TurboJPEG v3 can already handle JPEG images with unknown/arbitrary subsampling levels. It just can't perform lossless cropping, partial decompression, or decompression-to-YUV with such images, since those operations require knowing the iMCU size.