Skip to content

Commit

Permalink
Improve error message when trying to decode JPEG lossless images on t…
Browse files Browse the repository at this point in the history
…he CPU backend (NVIDIA#4587)

Signed-off-by: Joaquin Anton <janton@nvidia.com>
  • Loading branch information
jantonguirao authored and aderylo committed Mar 17, 2023
1 parent 51d0095 commit ae27d0b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 7 deletions.
20 changes: 19 additions & 1 deletion dali/imgcodec/decoders/opencv_fallback.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@
#include "dali/imgcodec/decoders/opencv_fallback.h"
#include "dali/imgcodec/util/convert.h"
#include "dali/imgcodec/registry.h"
#include "dali/imgcodec/parsers/jpeg.h"

namespace dali {
namespace imgcodec {
Expand Down Expand Up @@ -123,6 +124,23 @@ DecodeResult OpenCVDecoderInstance::DecodeImplTask(int thread_idx,
TensorLayout layout = cvimg.dims == 3 ? "DHWC" : "HWC";

Convert(out, layout, out_format, in, layout, in_format, roi, orientation);
} else {
JpegParser jpeg_parser{};
if (jpeg_parser.CanParse(in)) {
auto ext_info = jpeg_parser.GetExtendedInfo(in);
std::array<uint8_t, 2> sof3_marker = {0xff, 0xc3};
if (ext_info.sof_marker == sof3_marker) {
res.exception = std::make_exception_ptr(
std::runtime_error(
make_string(
"Failed to decode a JPEG lossless (SOF-3) sample: ", in->SourceInfo(), ".\n"
"Support for lossless is currently very limited:\n"
"- Only number of components <= 2\n"
"- Only predictor value 1\n"
"- Only \"mixed\" backend\n"
"If you used the \"cpu\" backend, please try the \"mixed\" one instead\n")));
}
}
}
} catch (...) {
res.exception = std::current_exception();
Expand Down
14 changes: 10 additions & 4 deletions dali/imgcodec/parsers/jpeg.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,7 +43,11 @@ bool IsSofMarker(const jpeg_marker_t &marker) {
}

ImageInfo JpegParser::GetInfo(ImageSource *encoded) const {
ImageInfo info{};
return GetExtendedInfo(encoded).img_info;
}

JpegParser::ExtendedImageInfo JpegParser::GetExtendedInfo(ImageSource *encoded) const {
JpegParser::ExtendedImageInfo info{};
auto stream = encoded->Open();

jpeg_marker_t first_marker = stream->ReadOne<jpeg_marker_t>();
Expand All @@ -67,11 +71,12 @@ ImageInfo JpegParser::GetInfo(ImageSource *encoded) const {
uint16_t size = ReadValueBE<uint16_t>(*stream);
ptrdiff_t next_marker_offset = stream->TellRead() - 2 + size;
if (IsSofMarker(marker)) {
info.sof_marker = marker;
stream->Skip(1); // Skip the precision field
auto height = ReadValueBE<uint16_t>(*stream);
auto width = ReadValueBE<uint16_t>(*stream);
auto nchannels = stream->ReadOne<uint8_t>();
info.shape = {height, width, nchannels};
info.img_info.shape = {height, width, nchannels};
read_shape = true;
} else if (marker == app1_marker && stream->ReadOne<jpeg_exif_header_t>() == exif_header) {
std::vector<uint8_t> exif_block(size - 8);
Expand All @@ -81,7 +86,8 @@ ImageInfo JpegParser::GetInfo(ImageSource *encoded) const {
continue;
auto entry = reader.getTag(cv::ORIENTATION);
if (entry.tag != cv::INVALID_TAG) {
info.orientation = FromExifOrientation(static_cast<ExifOrientation>(entry.field_u16));
info.img_info.orientation =
FromExifOrientation(static_cast<ExifOrientation>(entry.field_u16));
read_orientation = true;
}
}
Expand Down
8 changes: 7 additions & 1 deletion dali/imgcodec/parsers/jpeg.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,12 @@ class DLL_PUBLIC JpegParser : public ImageParser {
public:
ImageInfo GetInfo(ImageSource *encoded) const override;
bool CanParse(ImageSource *encoded) const override;

struct ExtendedImageInfo {
ImageInfo img_info;
std::array<uint8_t, 2> sof_marker;
};
ExtendedImageInfo GetExtendedInfo(ImageSource *encoded) const;
};

} // namespace imgcodec
Expand Down
5 changes: 4 additions & 1 deletion dali/test/python/decoder/test_imgcodec.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,4 +457,7 @@ def pipe(file):
imgfile = "db/single/jpeg_lossless/0/cat-1245673_640_grayscale_16bit.jpg"
p = pipe(os.path.join(test_data_root, imgfile))
p.build()
assert_raises(RuntimeError, p.run, glob='*') # Add glob pattern when we have a meaningful error

assert_raises(
RuntimeError, p.run,
glob='*Failed to decode a JPEG lossless (SOF-3)*Only "mixed" backend*')

0 comments on commit ae27d0b

Please sign in to comment.