Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@
path = ext/ffmpeg
url = https://github.com/FFmpeg/FFmpeg.git
shallow = true
[submodule "ext/OpenHTJ2K"]
path = ext/OpenHTJ2K
url = https://github.com/osamu620/OpenHTJ2K
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ add_library(libavutil STATIC IMPORTED)
add_dependencies(libavutil ffmpeg)
set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_INSTALL_DIR}/lib/libavutil.a)

# OpenHTJ2K support

add_subdirectory(ext/OpenHTJ2K)
include_directories(ext/OpenHTJ2K/src/core/interface)

# md5

include_directories(ext/crypto-algorithms)
Expand All @@ -83,7 +88,7 @@ add_library(md5 ext/crypto-algorithms/md5.c)

file(GLOB LIBENCH_SRC_FILES src/main/cpp/*)
add_executable(libench ${LIBENCH_SRC_FILES} ext/lodepng/lodepng.cpp)
target_link_libraries(libench openjph md5 jxl jxl_threads fast_lossless libavcodec libavutil ${KDU_LIBRARY} ${CMAKE_DL_LIBS})
target_link_libraries(libench openjph md5 jxl jxl_threads fast_lossless libavcodec libavutil open_htj2k ${KDU_LIBRARY} ${CMAKE_DL_LIBS})

# tests

Expand All @@ -99,3 +104,5 @@ add_test(NAME "j2k_1_kdu" COMMAND libench j2k_1_kdu ${PROJECT_SOURCE_DIR}/src/te
add_test(NAME "png" COMMAND libench png ${PROJECT_SOURCE_DIR}/src/test/resources/images/test1.png)
add_test(NAME "ffv1" COMMAND libench ffv1 ${PROJECT_SOURCE_DIR}/src/test/resources/images/test1.png)
add_test(NAME "ffv1-rgba" COMMAND libench ffv1 ${PROJECT_SOURCE_DIR}/src/test/resources/images/rgba.png)
add_test(NAME "j2k_ht_ohtj2k" COMMAND libench j2k_ht_ohtj2k ${PROJECT_SOURCE_DIR}/src/test/resources/images/test1.png)
add_test(NAME "j2k_ht_ohtj2ka" COMMAND libench j2k_ht_ohtj2k ${PROJECT_SOURCE_DIR}/src/test/resources/images/rgba.png)
1 change: 1 addition & 0 deletions ext/OpenHTJ2K
Submodule OpenHTJ2K added at 5265cc
4 changes: 4 additions & 0 deletions src/main/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern "C" {
#include "kduht_codec.h"
#include "png_codec.h"
#include "ffv1_codec.h"
#include "ohtj2k_codec.h"

#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
Expand Down Expand Up @@ -83,6 +84,9 @@ int main(int argc, char* argv[]) {
} else if (result["codec"].as<std::string>() == "qoi") {
encoder.reset(new libench::QOIEncoder());
decoder.reset(new libench::QOIDecoder());
} else if (result["codec"].as<std::string>() == "j2k_ht_ohtj2k") {
encoder.reset(new libench::OHTJ2KEncoder());
decoder.reset(new libench::OHTJ2KDecoder());
} else if (result["codec"].as<std::string>() == "jxl") {
encoder.reset(new libench::JXLEncoder<2>());
decoder.reset(new libench::JXLDecoder());
Expand Down
166 changes: 166 additions & 0 deletions src/main/cpp/ohtj2k_codec.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include "ohtj2k_codec.h"

#include <assert.h>

#include <memory>
#include <stdexcept>

constexpr uint32_t NUMTHREADS = 1;
/*
* OHTJ2KEncoder
*/

libench::OHTJ2KEncoder::OHTJ2KEncoder() : num_threads(NUMTHREADS){};

libench::CodestreamBuffer libench::OHTJ2KEncoder::encodeRGB8(
const uint8_t* pixels, uint32_t width, uint32_t height) {
return this->encode8(pixels, width, height, 3);
}

libench::CodestreamBuffer libench::OHTJ2KEncoder::encodeRGBA8(
const uint8_t* pixels, uint32_t width, uint32_t height) {
return this->encode8(pixels, width, height, 4);
}

libench::CodestreamBuffer libench::OHTJ2KEncoder::encode8(const uint8_t* pixels,
uint32_t width,
uint32_t height,
uint8_t num_comps) {
// siz
open_htj2k::siz_params siz;
siz.Rsiz = 0;
siz.Xsiz = width;
siz.Ysiz = height;
siz.XOsiz = 0;
siz.YOsiz = 0;
siz.XTsiz = 0;
siz.YTsiz = 0;
siz.XTOsiz = 0;
siz.YTOsiz = 0;
siz.Csiz = num_comps;
for (auto c = 0; c < siz.Csiz; ++c) {
siz.Ssiz.push_back(7);
auto compw = width;
auto comph = height;
siz.XRsiz.push_back(((siz.Xsiz - siz.XOsiz) + compw - 1) / compw);
siz.YRsiz.push_back(((siz.Ysiz - siz.YOsiz) + comph - 1) / comph);
}

// cod
open_htj2k::cod_params cod;
cod.blkwidth = 5; // 2^(5+2) = 128
cod.blkheight = 3; // 2^(3+2) = 32
cod.is_max_precincts = false;
cod.use_SOP = false;
cod.use_EPH = false;
cod.progression_order = 2;
cod.number_of_layers = 1;
cod.use_color_trafo = 1;
cod.dwt_levels = 6;
cod.codeblock_style = 0x040;
cod.transformation = 1;

for (size_t i = 0; i < 6; ++i) {
cod.PPx.push_back(8); // 2^8 = 256
cod.PPy.push_back(8);
}
cod.PPx.push_back(7); // 2^7 = 128
cod.PPy.push_back(7);

// qcd
open_htj2k::qcd_params qcd;
qcd.is_derived = false;
qcd.number_of_guardbits = 1;
qcd.base_step = 1.0 / 256;
if (qcd.base_step == 0.0) {
qcd.base_step = 1.0f / static_cast<float>(1 << 8);
}

bool isJPH = false;
uint8_t Qfactor = 0xff; // 0xff means no qfactor value is specified
uint8_t color_space = 0; // 0:RGB, 1:YCC

auto buf = std::make_unique<std::unique_ptr<int32_t[]>[]>(num_comps);
for (size_t i = 0; i < num_comps; ++i) {
buf[i] = std::make_unique<int32_t[]>(width * height);
}
std::vector<int32_t*> input_buf;
for (auto c = 0; c < num_comps; ++c) {
input_buf.push_back(buf[c].get());
}
const uint8_t* line = pixels;
for (uint32_t i = 0; i < height; ++i) {
for (uint32_t c = 0; c < num_comps; c++) {
const uint8_t* in = line + c;
int32_t* out = buf[c].get() + i * width;
for (uint32_t p = 0; p < width; p++) {
*out = *in;
out += 1;
in += num_comps;
}
}
line += num_comps * width;
}
open_htj2k::openhtj2k_encoder encoder("", input_buf, siz, cod, qcd, Qfactor,
isJPH, color_space, num_threads);
encoder.set_output_buffer(this->outbuf_);

size_t total_size = total_size = encoder.invoke();

libench::CodestreamBuffer cb;

cb.codestream = outbuf_.data();
cb.size = total_size;

return cb;
}

/*
* OHTJ2KDecoder
*/

libench::OHTJ2KDecoder::OHTJ2KDecoder() : num_threads(NUMTHREADS){};

libench::PixelBuffer libench::OHTJ2KDecoder::decodeRGB8(
const uint8_t* codestream, size_t size, uint32_t width, uint32_t height,
const uint8_t* init_data, size_t init_data_size) {
return this->decode8(codestream, size, 3);
}

libench::PixelBuffer libench::OHTJ2KDecoder::decodeRGBA8(
const uint8_t* codestream, size_t size, uint32_t width, uint32_t height,
const uint8_t* init_data, size_t init_data_size) {
return this->decode8(codestream, size, 4);
}

libench::PixelBuffer libench::OHTJ2KDecoder::decode8(const uint8_t* codestream,
size_t size,
uint8_t num_comps) {
open_htj2k::openhtj2k_decoder decoder(codestream, size, 0, num_threads);
std::vector<int32_t*> buf;
std::vector<uint32_t> img_width;
std::vector<uint32_t> img_height;
std::vector<uint8_t> img_depth;
std::vector<bool> img_signed;
decoder.invoke(buf, img_width, img_height, img_depth, img_signed);
uint32_t width = img_width[0];
uint32_t height = img_height[0];
this->pixels_.resize(width * height * num_comps);
for (uint32_t i = 0; i < height; ++i) {
uint8_t* line = &this->pixels_.data()[width * i * num_comps];
for (uint32_t c = 0; c < num_comps; c++) {
uint8_t* out = line + c;
int32_t* in = buf[c] + width * i;
for (uint32_t p = 0; p < width; p++) {
*out = *in;
out += num_comps;
in += 1;
}
}
}
libench::PixelBuffer pb = {.height = height,
.width = width,
.num_comps = num_comps,
.pixels = &this->pixels_.data()[0]};
return pb;
}
50 changes: 50 additions & 0 deletions src/main/cpp/ohtj2k_codec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef LIBENCH_OPENHTJ2K_H
#define LIBENCH_OPENHTJ2K_H

#include <vector>

#include "codec.h"
#include "decoder.hpp"
#include "encoder.hpp"

namespace libench {

class OHTJ2KEncoder : public Encoder {
public:
OHTJ2KEncoder();

virtual CodestreamBuffer encodeRGB8(const uint8_t* pixels,
const uint32_t width, uint32_t height);

virtual CodestreamBuffer encodeRGBA8(const uint8_t* pixels, uint32_t width,
uint32_t height);

private:
CodestreamBuffer encode8(const uint8_t* pixels, uint32_t width,
uint32_t height, uint8_t num_comps);
std::vector<uint8_t> outbuf_;
uint32_t num_threads;
};

class OHTJ2KDecoder : public Decoder {
public:
OHTJ2KDecoder();

virtual PixelBuffer decodeRGB8(const uint8_t* codestream, size_t size,
uint32_t width, uint32_t height,
const uint8_t* init_data,
size_t init_data_size);

virtual PixelBuffer decodeRGBA8(const uint8_t* codestream, size_t size,
uint32_t width, uint32_t height,
const uint8_t* init_data,
size_t init_data_size);

private:
PixelBuffer decode8(const uint8_t* codestream, size_t size,
uint8_t num_comps);
std::vector<uint8_t> pixels_;
uint32_t num_threads;
};
} // namespace libench
#endif