Skip to content

Commit afb3fbd

Browse files
committed
Add libaec-jna
Create new project wrapping libaec using JNA. The focus is on decoding libaec compressed buffers.
1 parent 39fa449 commit afb3fbd

File tree

6 files changed

+574
-0
lines changed

6 files changed

+574
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apply from: "$rootDir/gradle/any/dependencies.gradle"
2+
apply from: "$rootDir/gradle/any/java-library.gradle"
3+
4+
description = 'Java bindings for decoding libaec compression using JNA'
5+
ext.title = 'libaec compression decoder using JNA'
6+
7+
dependencies {
8+
api enforcedPlatform(project(':netcdf-java-platform'))
9+
testImplementation enforcedPlatform(project(':netcdf-java-testing-platform'))
10+
11+
api 'net.java.dev.jna:jna'
12+
implementation 'org.slf4j:slf4j-api'
13+
14+
testImplementation project(':cdm-test-utils')
15+
16+
testImplementation 'com.google.truth:truth'
17+
18+
testRuntimeOnly project(':native-compression:libaec-native')
19+
testRuntimeOnly 'ch.qos.logback:logback-classic'
20+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2025 University Corporation for Atmospheric Research/Unidata
3+
* See LICENSE for license information.
4+
*/
5+
6+
package edu.ucar.unidata.compression.jna.libaec;
7+
8+
import com.sun.jna.Memory;
9+
import com.sun.jna.Native;
10+
import com.sun.jna.Pointer;
11+
import com.sun.jna.Structure;
12+
import com.sun.jna.ptr.PointerByReference;
13+
import java.io.File;
14+
import java.io.IOException;
15+
import java.util.Arrays;
16+
import java.util.List;
17+
18+
/**
19+
* JNA access to libaec. Not a full implementation, just the functions
20+
* actually used for decoding (and testing). This is a transliteration
21+
* of the libaec library file include/libaec.h.
22+
*
23+
* @author sarms
24+
* @since 5.7.1
25+
*/
26+
27+
public final class LibAec {
28+
29+
private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LibAec.class);
30+
private static final String libName = "aec";
31+
32+
static {
33+
try {
34+
File library = Native.extractFromResourcePath(libName);
35+
Native.register(library.getAbsolutePath());
36+
log.debug("Using libaec library from libaec-native.jar");
37+
} catch (IOException e) {
38+
try {
39+
Native.register(libName);
40+
log.debug("Using libaec library from system");
41+
} catch (UnsatisfiedLinkError ule) {
42+
String message =
43+
"libaec C library not present. To read this data, include the libaec-native jar in your classpath "
44+
+ "(edu.ucar:libaec-native) or install libaec on your system.";
45+
log.error(message);
46+
throw new RuntimeException(message, ule);
47+
}
48+
}
49+
}
50+
51+
public static class AecStream extends Structure {
52+
public static AecStream create(int bitsPerSample, int blockSize, int rsi, int flags) {
53+
AecStream aecStream = new AecStream();
54+
aecStream.bits_per_sample = bitsPerSample;
55+
aecStream.block_size = blockSize;
56+
aecStream.rsi = rsi;
57+
aecStream.flags = flags;
58+
59+
return aecStream;
60+
}
61+
62+
public void setInputMemory(Memory inputMemory) {
63+
this.next_in = inputMemory;
64+
this.avail_in = new SizeT(inputMemory.size());
65+
}
66+
67+
public void setOutputMemory(Memory outputMemory) {
68+
this.next_out = outputMemory;
69+
this.avail_out = new SizeT(outputMemory.size());
70+
}
71+
72+
public Pointer next_in;
73+
// number of bytes available at next_in
74+
public SizeT avail_in;
75+
76+
// total number of input bytes read so far
77+
public SizeT total_in;
78+
79+
public Pointer next_out;
80+
81+
// remaining free space at next_out
82+
public SizeT avail_out;
83+
84+
// total number of bytes output so far
85+
public SizeT total_out;
86+
87+
// resolution in bits per sample (n = 1, ..., 32)
88+
public int bits_per_sample;
89+
90+
// block size in samples
91+
public int block_size;
92+
93+
// Reference sample interval, the number of blocks
94+
// between consecutive reference samples (up to 4096)
95+
public int rsi;
96+
97+
public int flags;
98+
99+
public volatile PointerByReference state;
100+
101+
@Override
102+
protected List<String> getFieldOrder() {
103+
return Arrays.asList("next_in", "avail_in", "total_in", "next_out", "avail_out", "total_out", "bits_per_sample",
104+
"block_size", "rsi", "flags", "state");
105+
}
106+
}
107+
108+
// Sample data description flags
109+
110+
// Samples are signed. Telling libaec this results in a slightly
111+
// better compression ratio. Default is unsigned.
112+
static final int AEC_DATA_SIGNED = 1;
113+
114+
// 24 bit samples are coded in 3 bytes
115+
static final int AEC_DATA_3BYTE = 2;
116+
117+
// Samples are stored with their most significant bit first. This has
118+
// nothing to do with the endianness of the host. Default is LSB.
119+
static final int AEC_DATA_MSB = 4;
120+
121+
// Set if preprocessor should be used
122+
static final int AEC_DATA_PREPROCESS = 8;
123+
124+
// Use restricted set of code options
125+
static final int AEC_RESTRICTED = 16;
126+
127+
128+
// Pad RSI to byte boundary. Only used for decoding some CCSDS sample
129+
// data. Do not use this to produce new data as it violates the
130+
// standard.
131+
static final int AEC_PAD_RSI = 32;
132+
133+
// Do not enforce standard regarding legal block sizes.
134+
static final int AEC_NOT_ENFORCE = 64;
135+
136+
// Return codes of library functions
137+
138+
public static final int AEC_OK = 0;
139+
public static final int AEC_CONF_ERROR = (-1);
140+
public static final int AEC_STREAM_ERROR = (-2);
141+
public static final int AEC_DATA_ERROR = (-3);
142+
public static final int AEC_MEM_ERROR = (-4);
143+
public static final int AEC_RSI_OFFSETS_ERROR = (-5);
144+
145+
// Options for flushing
146+
147+
// Do not enforce output flushing. More input may be provided with
148+
// later calls. So far only relevant for encoding.
149+
public static final int AEC_NO_FLUSH = 0;
150+
151+
// Flush output and end encoding. The last call to aec_encode() must
152+
// set AEC_FLUSH to drain all output.
153+
// It is not possible to continue encoding of the same stream after it
154+
// has been flushed. For one, the last block may be padded zeros after
155+
// preprocessing. Secondly, the last encoded byte may be padded with
156+
// fill bits.
157+
public static final int AEC_FLUSH = 1;
158+
159+
// Declare native methods corresponding to the functions in libaec.h
160+
// package private - for round trip testing only
161+
static native int aec_buffer_encode(AecStream strm);
162+
163+
public static native int aec_buffer_decode(AecStream strm);
164+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
3+
* See LICENSE for license information.
4+
*/
5+
6+
package edu.ucar.unidata.compression.jna.libaec;
7+
8+
import com.sun.jna.IntegerType;
9+
import com.sun.jna.Native;
10+
11+
/**
12+
* Map a native size_t with JNA.
13+
*
14+
* @see <a href="https://github.com/twall/jna/issues/191" />
15+
*/
16+
public class SizeT extends IntegerType {
17+
public SizeT() {
18+
this(0);
19+
}
20+
21+
public SizeT(long value) {
22+
super(Native.SIZE_T_SIZE, value, true);
23+
}
24+
25+
public String toString() {
26+
return String.format("%d", super.longValue());
27+
}
28+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/**
2+
* @file libaec.h
3+
*
4+
* @section LICENSE
5+
* Copyright 2024 Mathis Rosenhauer, Moritz Hanke, Joerg Behrens, Luis Kornblueh
6+
* All rights reserved.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright
13+
* notice, this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer in the documentation and/or other materials provided
17+
* with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30+
* OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*
32+
* @section DESCRIPTION
33+
*
34+
* Adaptive Entropy Coding library
35+
*
36+
*/
37+
38+
#ifndef LIBAEC_H
39+
#define LIBAEC_H 1
40+
41+
#define AEC_VERSION_MAJOR 1
42+
#define AEC_VERSION_MINOR 1
43+
#define AEC_VERSION_PATCH 3
44+
#define AEC_VERSION_STR "1.1.3"
45+
46+
#include <stddef.h>
47+
48+
#ifdef __cplusplus
49+
extern "C"{
50+
#endif
51+
52+
#if defined LIBAEC_BUILD && HAVE_VISIBILITY
53+
# define LIBAEC_DLL_EXPORTED __attribute__((__visibility__("default")))
54+
#elif (defined _WIN32 && !defined __CYGWIN__) && defined LIBAEC_SHARED
55+
# if defined LIBAEC_BUILD
56+
# define LIBAEC_DLL_EXPORTED __declspec(dllexport)
57+
# else
58+
# define LIBAEC_DLL_EXPORTED __declspec(dllimport)
59+
# endif
60+
#else
61+
# define LIBAEC_DLL_EXPORTED
62+
#endif
63+
64+
struct internal_state;
65+
66+
struct aec_stream {
67+
const unsigned char *next_in;
68+
69+
/* number of bytes available at next_in */
70+
size_t avail_in;
71+
72+
/* total number of input bytes read so far */
73+
size_t total_in;
74+
75+
unsigned char *next_out;
76+
77+
/* remaining free space at next_out */
78+
size_t avail_out;
79+
80+
/* total number of bytes output so far */
81+
size_t total_out;
82+
83+
/* resolution in bits per sample (n = 1, ..., 32) */
84+
unsigned int bits_per_sample;
85+
86+
/* block size in samples */
87+
unsigned int block_size;
88+
89+
/* Reference sample interval, the number of blocks
90+
* between consecutive reference samples (up to 4096). */
91+
unsigned int rsi;
92+
93+
unsigned int flags;
94+
95+
struct internal_state *state;
96+
};
97+
98+
/*********************************/
99+
/* Sample data description flags */
100+
/*********************************/
101+
102+
/* Samples are signed. Telling libaec this results in a slightly
103+
* better compression ratio. Default is unsigned. */
104+
#define AEC_DATA_SIGNED 1
105+
106+
/* 24 bit samples are coded in 3 bytes */
107+
#define AEC_DATA_3BYTE 2
108+
109+
/* Samples are stored with their most significant bit first. This has
110+
* nothing to do with the endianness of the host. Default is LSB. */
111+
#define AEC_DATA_MSB 4
112+
113+
/* Set if preprocessor should be used */
114+
#define AEC_DATA_PREPROCESS 8
115+
116+
/* Use restricted set of code options */
117+
#define AEC_RESTRICTED 16
118+
119+
/* Pad RSI to byte boundary. Only used for decoding some CCSDS sample
120+
* data. Do not use this to produce new data as it violates the
121+
* standard. */
122+
#define AEC_PAD_RSI 32
123+
124+
/* Do not enforce standard regarding legal block sizes. */
125+
#define AEC_NOT_ENFORCE 64
126+
127+
/*************************************/
128+
/* Return codes of library functions */
129+
/*************************************/
130+
#define AEC_OK 0
131+
#define AEC_CONF_ERROR (-1)
132+
#define AEC_STREAM_ERROR (-2)
133+
#define AEC_DATA_ERROR (-3)
134+
#define AEC_MEM_ERROR (-4)
135+
#define AEC_RSI_OFFSETS_ERROR (-5)
136+
137+
/************************/
138+
/* Options for flushing */
139+
/************************/
140+
141+
/* Do not enforce output flushing. More input may be provided with
142+
* later calls. So far only relevant for encoding. */
143+
#define AEC_NO_FLUSH 0
144+
145+
/* Flush output and end encoding. The last call to aec_encode() must
146+
* set AEC_FLUSH to drain all output.
147+
*
148+
* It is not possible to continue encoding of the same stream after it
149+
* has been flushed. For one, the last block may be padded zeros after
150+
* preprocessing. Secondly, the last encoded byte may be padded with
151+
* fill bits. */
152+
#define AEC_FLUSH 1
153+
154+
/*********************************************/
155+
/* Streaming encoding and decoding functions */
156+
/*********************************************/
157+
LIBAEC_DLL_EXPORTED int aec_encode_init(struct aec_stream *strm);
158+
LIBAEC_DLL_EXPORTED int aec_encode_enable_offsets(struct aec_stream *strm);
159+
LIBAEC_DLL_EXPORTED int aec_encode_count_offsets(struct aec_stream *strm, size_t *rsi_offsets_count);
160+
LIBAEC_DLL_EXPORTED int aec_encode_get_offsets(struct aec_stream *strm, size_t *rsi_offsets, size_t rsi_offsets_count);
161+
LIBAEC_DLL_EXPORTED int aec_buffer_seek(struct aec_stream *strm, size_t offset);
162+
LIBAEC_DLL_EXPORTED int aec_encode(struct aec_stream *strm, int flush);
163+
LIBAEC_DLL_EXPORTED int aec_encode_end(struct aec_stream *strm);
164+
165+
LIBAEC_DLL_EXPORTED int aec_decode_init(struct aec_stream *strm);
166+
LIBAEC_DLL_EXPORTED int aec_decode_enable_offsets(struct aec_stream *strm);
167+
LIBAEC_DLL_EXPORTED int aec_decode_count_offsets(struct aec_stream *strm, size_t *rsi_offsets_count);
168+
LIBAEC_DLL_EXPORTED int aec_decode_get_offsets(struct aec_stream *strm, size_t *rsi_offsets, size_t rsi_offsets_count);
169+
LIBAEC_DLL_EXPORTED int aec_decode(struct aec_stream *strm, int flush);
170+
LIBAEC_DLL_EXPORTED int aec_decode_range(struct aec_stream *strm, const size_t *rsi_offsets, size_t rsi_offsets_count, size_t pos, size_t size);
171+
LIBAEC_DLL_EXPORTED int aec_decode_end(struct aec_stream *strm);
172+
173+
/***************************************************************/
174+
/* Utility functions for encoding or decoding a memory buffer. */
175+
/***************************************************************/
176+
LIBAEC_DLL_EXPORTED int aec_buffer_encode(struct aec_stream *strm);
177+
LIBAEC_DLL_EXPORTED int aec_buffer_decode(struct aec_stream *strm);
178+
179+
#ifdef __cplusplus
180+
}
181+
#endif
182+
183+
#endif /* LIBAEC_H */

0 commit comments

Comments
 (0)