bpg_api.dll is a stable C ABI for in-memory BPG processing on Windows:
- convert JPEG, PNG, or BMP bytes to a still BPG;
- encode packed RGB frames as an animated BPG;
- decode still or animated BPG bytes frame by frame to BGRA8;
- keep all codec input, intermediate data, and output callbacks in memory.
The DLL itself opens no files and performs no disk I/O. Your application decides whether bytes are kept in RAM, sent over a network, or written to storage.
New integrations should use the size-versioned
*_v1API. The legacy API remains exported for binary compatibility.
| Item | SDK 1.0.0 |
|---|---|
| Operating system | Windows 10/11 x64 |
| ABI | C, __cdecl, undecorated export names |
| Still input | JPEG, PNG, uncompressed 24/32-bit BMP |
| Animated encoder input | RGB24 and RGB48 |
| Decoder output | BGRA32 (8 bits per channel) |
| Still alpha | Supported for suitable PNG/BMP input |
| Animated alpha encoding | Not supported by this build; RGBA input returns BPG_ERR_UNSUPPORTED |
| Animated alpha decoding | Supported |
| Per-frame timing | Rational duration in seconds |
| File I/O inside DLL | None |
Animated alpha encoding is deliberately rejected. The bundled x265 revision is unsafe while flushing delayed monochrome frames used by the BPG alpha layer. Returning BPG_ERR_UNSUPPORTED prevents a process crash. Do not strip this guard unless replacing and fully testing the encoder backend.
A release archive contains:
bin/
bpg_api.dll
libjpeg-8.dll
libpng16-16.dll
libwinpthread-1.dll
libgcc_s_seh-1.dll
zlib1.dll
include/
bpg_api.h
lib/
libbpg_api.a # MinGW/GNU import library
bpg_api.lib # MSVC x64 COFF import library
examples/
licenses/
README_BPG_API.md
DISTRIBUTION.md
THIRD_PARTY_NOTICES.md
RELEASE_CHECKLIST.md
SHA256SUMS.txt
Keep the DLL and all five non-system runtime DLLs beside the application executable, or place them in another directory selected by a secure DLL-loading policy. Do not rely on the current working directory or a globally modified PATH in production.
This example converts an already-loaded image buffer to BPG. It performs no file I/O.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bpg_api.h"
int encode_image(const uint8_t *source, uint64_t source_len)
{
BPGConvertConfigV1 config;
uint8_t *bpg = NULL;
uint64_t bpg_len = 0;
int32_t result;
memset(&config, 0, sizeof(config));
config.struct_size = sizeof(config);
config.qp = 28;
config.bit_depth = 8;
config.compress_level = 6;
result = bpg_convert_v1(source, source_len, &config, &bpg, &bpg_len);
if (result != BPG_OK) {
fprintf(stderr, "BPG encode failed: %s (%d)\n",
bpg_error_string(result), (int)result);
return 0;
}
/* Use bpg[0..bpg_len): retain in RAM, send, or write it yourself. */
printf("encoded %llu bytes\n", (unsigned long long)bpg_len);
bpg_free(bpg);
return 1;
}cl /nologo /W4 /Iinclude your_app.c /link /LIBPATH:lib bpg_api.libgcc -O2 -Wall -Wextra -Iinclude -o your_app.exe your_app.c -Llib -lbpg_apiAt runtime, place the contents of bin/ next to your_app.exe.
| Goal | Recommended API |
|---|---|
| Convert one JPEG/PNG/BMP buffer | bpg_convert_v1 |
| Encode a sequence of raw RGB frames | bpg_anim_open_v1 → bpg_anim_add_frame_v1 → bpg_anim_finish_v1 |
| Cancel an animation | bpg_anim_abort_v1 |
| Inspect/decode BPG frames | bpg_decode_open_v1 → bpg_decode_next_frame_v1 → bpg_decode_close_v1 |
| Check runtime compatibility | bpg_api_version and bpg_api_capabilities |
| Maintain an existing integration | Legacy exports remain available; migrate when practical |
Every v1 structure starts with struct_size.
- Zero the entire structure.
- Set
struct_size = sizeof(structure). - Set only documented fields.
- Leave all
reservedfields zero.
Example:
BPGAnimEncoderConfigV1 config;
memset(&config, 0, sizeof(config));
config.struct_size = sizeof(config);The DLL accepts a structure at least as large as the v1 definition and ignores unknown tail fields. A smaller structure returns BPG_ERR_INVALID_PARAM.
int32_t bpg_convert_v1(
const uint8_t *input_data,
uint64_t input_len,
const BPGConvertConfigV1 *config,
uint8_t **out_buf,
uint64_t *out_len);| Field | Values | Default |
|---|---|---|
qp |
0..51; lower usually means higher quality/larger output |
-1 selects 29 |
lossless |
0 or 1 |
0 |
bit_depth |
8, 10, or 12 |
0 selects 8 |
compress_level |
1..9; higher is slower |
0 selects 8 |
prefer_444 |
0 for 4:2:0, 1 for 4:4:4 |
0 |
On success, the DLL allocates *out_buf and sets *out_len. Release the buffer only with bpg_free(). On failure, outputs are reset to NULL and zero.
Do not pass a still-owned output pointer back as out_buf for another call: because outputs are reset on entry, doing so would lose your original pointer. Free the previous result first.
| Format | Detection and support |
|---|---|
| JPEG | FF D8; grayscale, YCbCr, RGB, YCCK, and CMYK paths supported by the bundled decoder |
| PNG | PNG signature; 8/16-bit grayscale, palette, RGB, and alpha variants |
| BMP | BM; uncompressed 24-bit and 32-bit BMP |
Unknown signatures return BPG_ERR_UNKNOWN_FORMAT. Recognized but malformed data returns BPG_ERR_DECODE_FAILED.
void *encoder = NULL;
int32_t result;
result = bpg_anim_open_v1(&config, write_callback, opaque, &encoder);
if (result != BPG_OK)
return result;
/* Submit one or more RGB frames. */
result = bpg_anim_finish_v1(&encoder);
/* encoder is NULL after finish, including on failure. */If any operation fails and the handle is still non-null, call:
bpg_anim_abort_v1(&encoder);bpg_anim_abort_v1 consumes the session, releases retained codec output, and sets the caller's handle to NULL. Calling it with a valid pointer whose contained handle is already NULL succeeds.
Finishing a zero-frame session returns BPG_ERR_BAD_STATE, still releases the session, and still nulls the handle.
| Field | Meaning |
|---|---|
width, height |
Fixed dimensions for every frame; nonzero |
qp |
-1 for 29 or 0..51 |
fps_num / fps_den |
Frame rate, for example 30/1 or 30000/1001; each component must fit 1..65535 |
loop_count |
0 means infinite; maximum 65535 |
compress_level |
0 for 8 or 1..9 |
prefer_444 |
0 for 4:2:0, 1 for 4:4:4 |
lossless |
0 or 1; lossless forces RGB 4:4:4 internally |
The frame duration reported by the decoder is the inverse frame rate. A 30/1 FPS configuration normally decodes as duration 1/30 second.
int32_t bpg_anim_add_frame_v1(
void *handle,
const uint8_t *pixels,
uint64_t pixels_len,
uint32_t stride,
uint32_t pixel_format,
uint32_t limited_range);Supported encoder formats:
| Constant | Layout | Bytes/pixel |
|---|---|---|
BPG_PIXFMT_RGB24 |
R8 G8 B8 | 3 |
BPG_PIXFMT_RGB48 |
native-endian R16 G16 B16 | 6 |
BPG_PIXFMT_RGBA32 and BPG_PIXFMT_RGBA64 are defined for ABI stability but animated alpha encoding returns BPG_ERR_UNSUPPORTED in SDK 1.0.0.
The packed row size is:
row_bytes = width * bytes_per_pixel
Requirements:
stride >= row_bytes
pixels_len >= stride * (height - 1) + row_bytes
For 16-bit input, the base pointer and stride must be 2-byte aligned. The pixel buffer remains caller-owned and needs to stay valid only until bpg_anim_add_frame_v1 returns. The DLL converts/copies frame pixels during the call.
typedef int32_t (__cdecl *BPGAnimWriteFuncV1)(
void *opaque,
const uint8_t *buf,
uint32_t buf_len);- Return
0after consuming/copying all bytes. - Return nonzero to abort output.
bufis borrowed and valid only until the callback returns.- Do not retain
buf; copy it if asynchronous use is required. - The callback may be invoked while adding the first frame and/or while finishing.
- A callback rejection is reported as
BPG_ERR_CALLBACK_FAILED. - Do not call encoder functions recursively from its own callback.
For long recordings, stream callback chunks directly to a bounded application pipeline or final destination. Accumulating every callback chunk in one growable memory buffer increases peak RAM use.
BPGDecodeInfoV1 info;
void *decoder = NULL;
memset(&info, 0, sizeof(info));
info.struct_size = sizeof(info);
result = bpg_decode_open_v1(bpg_data, bpg_len, &info, &decoder);On success, info reports dimensions, alpha/animation flags, loop count, and BPG_PIXFMT_BGRA32. The decoder copies/retains the encoded payload it needs, so the caller may release the source BPG buffer after open returns.
BPGDecodedFrameV1 frame;
memset(&frame, 0, sizeof(frame));
frame.struct_size = sizeof(frame);
result = bpg_decode_next_frame_v1(
decoder, bgra, bgra_len, bgra_stride, &frame);Return values:
1: one frame was written;0: end of stream;- negative:
BPG_ERR_*failure.
The BGRA capacity rule is:
row_bytes = width * 4
bgra_stride >= row_bytes
bgra_len >= bgra_stride * (height - 1) + row_bytes
Reuse one caller-owned output buffer for all frames. frame.frame_index starts at zero. frame.delay_num / frame.delay_den is the current frame duration in seconds, with a nonzero denominator.
Upstream libbpg does not distinguish normal animation end from malformed trailing animation payload after earlier frames have decoded. The wrapper preserves legacy behavior and reports that condition as EOS. A malformed header or initial frame is rejected by bpg_decode_open_v1.
bpg_decode_close_v1(&decoder);The function releases the decoder and sets the handle to NULL. A valid pointer containing a null handle is accepted.
| Object | Owner | Valid until / release |
|---|---|---|
| Still input bytes | Caller | Until bpg_convert_v1 returns |
| Still BPG output | DLL transfers to caller | bpg_free |
| Encoder config | Caller | Until bpg_anim_open_v1 returns |
| Submitted frame pixels | Caller | Until bpg_anim_add_frame_v1 returns |
Callback buf |
DLL | Callback return only |
| Encoder handle | DLL, referenced by caller | bpg_anim_finish_v1 or bpg_anim_abort_v1 |
| BPG bytes passed to decoder open | Caller | May release after successful open |
| BGRA output buffer | Caller | Caller-controlled and reusable |
| Decoder handle | DLL, referenced by caller | bpg_decode_close_v1 |
| Error/version strings | DLL static storage | Do not free or modify |
Never use C free(), C++ delete, or another runtime allocator for memory returned by the DLL. Use bpg_free().
| Value | Constant | Meaning |
|---|---|---|
| 0 | BPG_OK |
Success |
| -1 | BPG_ERR_INVALID_PARAM |
Null pointer, invalid range, stride, alignment, or structure size |
| -2 | BPG_ERR_UNKNOWN_FORMAT |
Still input signature is unsupported |
| -3 | BPG_ERR_DECODE_FAILED |
Recognized input could not be decoded |
| -4 | BPG_ERR_ENCODE_FAILED |
Codec or BPG construction failure |
| -5 | BPG_ERR_OUT_OF_MEMORY |
Allocation failed |
| -6 | BPG_ERR_BUFFER_TOO_SMALL |
Declared input/output capacity is insufficient |
| -7 | BPG_ERR_CALLBACK_FAILED |
Output callback returned nonzero |
| -8 | BPG_ERR_BAD_STATE |
Invalid lifecycle state, including finishing zero frames |
| -9 | BPG_ERR_UNSUPPORTED |
Valid but unsupported format/option in this build |
bpg_error_string(code) returns a static English diagnostic. Log both the numeric code and text; do not parse the text programmatically.
uint32_t packed = bpg_api_version(); /* 0xMMmmpp */
const char *text = bpg_api_version_string();
uint64_t caps = bpg_api_capabilities();SDK 1.0.0 returns packed version 0x010000. Check the major version before relying on ABI compatibility and use capability bits when features are optional.
The Windows file resource reports file version 1.0.0.0 and product version 1.0.0.
Verified behavior:
- independent encoder/decoder sessions can run concurrently on separate threads;
- release tests run four threads, each creating three independent encode/decode sessions;
- each handle, callback state, and input/output buffer is owned by one thread at a time.
Unsupported behavior:
- concurrent calls using the same encoder or decoder handle;
- closing/aborting a handle while another thread is using it;
- sharing mutable callback state without application synchronization;
- recursive API calls on the same session from its output callback.
Use one session per worker or externally serialize each handle.
- Reuse capture and BGRA decode buffers.
- Submit contiguous frames directly; the v1 wrapper allocates its row-pointer table once per encoder session.
- Keep the output callback short. Copy or enqueue bytes and return.
- Prefer a bounded queue when the final sink can stall.
- Avoid an extra full-file accumulation buffer for long recordings.
compress_leveltrades CPU time for compression; benchmark representative screen content.- 4:2:0 usually reduces output size; 4:4:4 preserves sharp colored text better at higher cost.
- Encoder sessions retain x265 output until delayed frames are flushed, so peak memory is not strictly constant with recording duration.
- The DLL performs no file I/O, but x265/libpng/libjpeg allocate internal memory.
The following original names remain exported unchanged:
bpg_convert
bpg_convert_ex
bpg_free
bpg_error_string
bpg_anim_begin
bpg_anim_add_frame
bpg_anim_end
bpg_decode_open
bpg_decode_next_frame
bpg_decode_close
Existing binaries can continue to load these symbols. New code should prefer v1 because it adds:
- fixed-width ABI fields;
- size-versioned structures;
- explicit open errors;
- total buffer-length checks;
- contiguous frame input;
- distinct finish and abort operations;
- caller-handle nulling;
- version and capability queries.
The legacy animated-alpha path now also returns BPG_ERR_UNSUPPORTED to prevent the bundled x265 crash.
Install MSYS2, then from an MSYS2 MinGW x64 shell:
pacman -S mingw-w64-x86_64-gcc \
mingw-w64-x86_64-libpng \
mingw-w64-x86_64-libjpeg-turbo \
make cmakebuild.bat clean
build.bat
build.bat test
build.bat verifybuild.bat test is the release gate for native behavior. It runs:
- legacy still-image self-tests;
- v1 contract tests;
- independent-session concurrency stress;
- exact export-set comparison against
expected_exports_v1.txt.
make -f Makefile.win
make -f Makefile.win test
make -f Makefile.win verify-exports
make -f Makefile.win cleanBuild products:
| File | Purpose |
|---|---|
bpg_api.dll |
Versioned Windows x64 DLL |
libbpg_api.a |
MinGW/GNU import library |
bpg_api.lib |
MSVC-compatible x64 COFF import library |
bpg_api.h |
Public ABI header |
The .def file is the authoritative public export list.
Copy all release bin/ DLLs next to the executable. A source-tree build directly imports:
libjpeg-8.dll
libpng16-16.dll
libwinpthread-1.dll
Their transitive non-system imports require:
libgcc_s_seh-1.dll
zlib1.dll
Use dumpbin /dependents bpg_api.dll or objdump -p bpg_api.dll to inspect the exact binary being deployed.
SDK 1.0.0 is x64 only. The application and every dependency must also be x64.
Use the last-row formulas documented above. stride * height is safe but may be larger than required; stride * (height - 1) + row_bytes is exact.
The callback returned nonzero. Preserve the original sink error in callback-owned state, then abort the still-live encoder handle if necessary.
This is expected in SDK 1.0.0. Composite to RGB before submission or replace and qualify the encoder backend.
This is an upstream libbpg limitation: normal EOS and malformed trailing animation data share one return path. Validate transport length/checksums outside the decoder when truncation detection is required.
Benchmark qp, compress_level, and chroma mode with representative content. Lower QP and 4:4:4 usually increase size. Higher compression levels usually increase CPU time.
- Treat all image/BPG input as untrusted.
- Enforce application-level size, duration, and frame-count limits before allocating large buffers.
- Do not load dependency DLLs from writable or ambiguous search paths.
- Keep the DLL and dependency set together and verify release checksums/signatures.
- Run malformed-input tests and dependency inspection for every release.
The project combines components under multiple licenses. The encoder build statically links x265. Community distribution of that combined encoder DLL is intended for the GPL-2.0-or-later path and must satisfy the corresponding source/notice obligations. Organizations that cannot use that path should obtain appropriate commercial x265 licensing and perform their own legal review.
libbpg wrapper/core files, decoder-derived files, libpng, libjpeg-turbo, zlib, MinGW runtimes, and other bundled components have separate notices and conditions. HEVC may also be subject to patent licensing requirements depending on product, use, and jurisdiction.
Read DISTRIBUTION.md, THIRD_PARTY_NOTICES.md, and the packaged licenses/ directory before redistribution. These documents provide engineering guidance, not legal advice.
bpg_api.h: authoritative declarations and constants.examples/: complete C/C++, Rust, Python, and C# integrations.RELEASE_CHECKLIST.md: publication gate.DISTRIBUTION.md: distribution and source-offer guidance.THIRD_PARTY_NOTICES.md: component inventory and notices.