blob: 8d571a41ad7b6a91fac8c349f6c4a06c03d6103c [file] [edit]
// Copyright (c) Google LLC 2019
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
#include <brunsli/brunsli_decode.h>
#include <brunsli/brunsli_encode.h>
#include <brunsli/jpeg_data_reader.h>
#include <brunsli/jpeg_data_writer.h>
#include <string>
extern "C" {
std::string* BrunsliToJpeg(const uint8_t* data, size_t length) {
std::string* result = nullptr;
brunsli::JPEGData jpg;
brunsli::BrunsliStatus status =
brunsli::BrunsliDecodeJpeg(data, length, &jpg);
if (status != brunsli::BRUNSLI_OK) {
printf("Decoding Brunsli failed with status %d\n", status);
return result;
}
result = new std::string();
auto write = [](void* data, const uint8_t* buf, size_t count) -> size_t {
std::string* result = reinterpret_cast<std::string*>(data);
result->append(reinterpret_cast<const char*>(buf), count);
return count;
};
brunsli::JPEGOutput writer(write, result);
if (!brunsli::WriteJpeg(jpg, writer)) {
printf("Serializing JPEG failed\n");
delete result;
result = nullptr;
}
return result;
}
/*
* Instance layout (uint32 array):
* 0: decoder
* 1: max_in_len
* 2: in
* 3: in_len - the only writable field
* 4: out
* 5: out_len
*/
static const size_t kBufferSize = 65536;
uint32_t* BrunsliDecoderInit() {
uint32_t* instance = new uint32_t[6];
// TODO(eustas): check for OOMs
brunsli::BrunsliDecoder* decoder = new brunsli::BrunsliDecoder();
uint8_t* in = reinterpret_cast<uint8_t*>(malloc(kBufferSize));
uint8_t* out = reinterpret_cast<uint8_t*>(malloc(kBufferSize));
instance[0] = reinterpret_cast<uint32_t>(decoder);
instance[1] = kBufferSize;
instance[2] = reinterpret_cast<uint32_t>(in);
instance[3] = 0;
instance[4] = reinterpret_cast<uint32_t>(out);
instance[5] = 0;
return instance;
}
/*
* Parse input and produce output.
*
* Input should be passed via `in_len`; data have to be stored starting at `in`.
* It is considered that all input is consumed.
* After invocation `out_len` output bytes are placed at `out`.
* It is considered that client consumes all the output right after inovcation.
*
* Result:
* 0: ok - keep feeding input / consuming output
* 1: done - no more input / output
* 2: error
*/
uint32_t BrunsliDecoderProcess(uint32_t* instance) {
brunsli::BrunsliDecoder* decoder =
reinterpret_cast<brunsli::BrunsliDecoder*>(instance[0]);
const uint8_t* next_in = reinterpret_cast<uint8_t*>(instance[2]);
size_t available_in = instance[3];
uint8_t* next_out = reinterpret_cast<uint8_t*>(instance[4]);
size_t available_out = kBufferSize;
brunsli::BrunsliDecoder::Status result =
decoder->Decode(&available_in, &next_in, &available_out, &next_out);
instance[5] = kBufferSize - available_out;
if ((result == brunsli::BrunsliDecoder::NEEDS_MORE_INPUT) ||
(result == brunsli::BrunsliDecoder::NEEDS_MORE_OUTPUT)) {
return 0;
}
if (result == brunsli::BrunsliDecoder::DONE) return 1;
return 2;
}
void BrunsliDecoderCleanup(uint32_t* instance) {
if (instance == nullptr) return;
brunsli::BrunsliDecoder* decoder =
reinterpret_cast<brunsli::BrunsliDecoder*>(instance[0]);
delete decoder;
uint8_t* in = reinterpret_cast<uint8_t*>(instance[2]);
delete[] in;
uint8_t* out = reinterpret_cast<uint8_t*>(instance[4]);
delete[] out;
delete[] instance;
}
const char* GetJpegData(std::string* jpeg) {
if (!jpeg) return 0;
return jpeg->data();
}
size_t GetJpegLength(std::string* jpeg) {
if (!jpeg) return 0;
return jpeg->size();
}
void FreeJpeg(std::string* jpeg) { delete jpeg; }
std::string* JpegToBrunsli(const uint8_t* data, size_t length) {
std::string* result = nullptr;
brunsli::JPEGData jpg;
if (!brunsli::ReadJpeg(data, length, brunsli::JPEG_READ_ALL, &jpg)) {
printf("Parsing JPEG failed\n");
return result;
}
size_t result_length = brunsli::GetMaximumBrunsliEncodedSize(jpg);
result = new std::string();
result->resize(result_length);
bool ok = brunsli::BrunsliEncodeJpeg(
jpg, reinterpret_cast<uint8_t*>(&result->at(0)), &result_length);
if (ok) {
result->resize(result_length);
} else {
printf("Encoding Brunsli failed\n");
delete result;
result = nullptr;
}
return result;
}
const char* GetBrunsliData(std::string* brunsli) {
if (!brunsli) return 0;
return brunsli->data();
}
size_t GetBrunsliLength(std::string* brunsli) {
if (!brunsli) return 0;
return brunsli->size();
}
void FreeBrunsli(std::string* brunsli) { delete brunsli; }
} // extern "C"