-
Notifications
You must be signed in to change notification settings - Fork 399
Improve encode c api #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve encode c api #145
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| #include "cimbar_js.h" | ||
|
|
||
| #include "cimb_translator/Config.h" | ||
| #include "compression/zstd_compressor.h" | ||
| #include "encoder/Encoder.h" | ||
| #include "gui/window_glfw.h" | ||
| #include "util/byte_istream.h" | ||
|
|
@@ -15,7 +16,12 @@ namespace { | |
| std::shared_ptr<fountain_encoder_stream> _fes; | ||
| std::optional<cv::Mat> _next; | ||
|
|
||
| // compressing the file | ||
| std::unique_ptr<cimbar::zstd_compressor<std::stringstream>> _comp; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The downside here is that the compression is now stateful. But it must be, given that want to persist state across calls. |
||
|
|
||
| int _frameCount = 0; | ||
| // start encode_id is 109. This is mostly unimportant (it only needs to wrap between [0,127]), but useful | ||
| // for the decoder -- because it gives it a better distribution of colors in the first frame header it sees. | ||
| uint8_t _encodeId = 109; | ||
|
|
||
| // settings, will be overriden by first call to configure() | ||
|
|
@@ -108,7 +114,11 @@ int cimbare_next_frame() | |
| return ++_frameCount; | ||
| } | ||
|
|
||
| int cimbare_encode(const unsigned char* buffer, unsigned size, const char* filename, unsigned fnsize, int encode_id) | ||
| // maybe init_encode w/ filename,size,encode_id, | ||
| // then encode() with buff,size? ... when size < chunksize (or size ==0), we're done | ||
| // return 0 on done, 1 iff work to continue? | ||
|
|
||
| int cimbare_init_encode(const char* filename, unsigned fnsize, int encode_id) | ||
| { | ||
| _frameCount = 0; | ||
| if (!FountainInit::init()) | ||
|
|
@@ -117,17 +127,51 @@ int cimbare_encode(const unsigned char* buffer, unsigned size, const char* filen | |
| return -5; | ||
| } | ||
|
|
||
| Encoder enc; | ||
| if (encode_id < 0) | ||
| enc.set_encode_id(++_encodeId); // increment _encodeId every time we change files | ||
| ++_encodeId; // increment _encodeId every time we change files | ||
| else | ||
| enc.set_encode_id(static_cast<uint8_t>(encode_id)); | ||
| _encodeId = encode_id; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be the strangest side effect of this change -- (should probably define a constant for that) |
||
|
|
||
| _comp = std::make_unique<cimbar::zstd_compressor<std::stringstream>>(); | ||
| if (!_comp) | ||
| return -1; | ||
|
|
||
| _comp->set_compression_level(_compressionLevel); | ||
|
|
||
| if (fnsize > 0 and filename != nullptr) | ||
| _comp->write_header(filename, fnsize); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this "new" code is refactored from |
||
| return 0; | ||
| } | ||
|
|
||
| int cimbare_encode_bufsize() | ||
| { | ||
| return cimbar::zstd_compressor<std::stringstream>::CHUNK_SIZE; | ||
| } | ||
|
|
||
| cimbar::byte_istream bis(reinterpret_cast<const char*>(buffer), size); | ||
| _fes = enc.create_fountain_encoder(bis, std::string_view(filename, fnsize), _compressionLevel); | ||
| int cimbare_encode(const unsigned char* buffer, unsigned size) | ||
| { | ||
| if (!_comp) | ||
| return -1; | ||
|
|
||
| if (size > 0) | ||
| { | ||
| if (!_comp->write(reinterpret_cast<const char*>(buffer), size)) | ||
| return -2; | ||
| } | ||
| if (size == cimbare_encode_bufsize()) | ||
| return 1; // more to do | ||
|
|
||
| // otherwise, we're ready | ||
| unsigned fountainChunkSize = cimbar::Config::fountain_chunk_size(); | ||
| size_t compressedSize = _comp->size(); | ||
| if (compressedSize < fountainChunkSize) | ||
| _comp->pad(fountainChunkSize - compressedSize + 1); | ||
|
|
||
| // create the encoder stream | ||
| _fes = fountain_encoder_stream::create(*_comp, fountainChunkSize, _encodeId); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More from |
||
| _comp.reset(); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After we return 0 from |
||
| if (!_fes) | ||
| return -1; // return -1 plz | ||
| return -3; | ||
|
|
||
| _next.reset(); | ||
| return 0; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,7 +33,8 @@ TEST_CASE( "cimbar_jsTest/testRoundtrip", "[unit]" ) | |
| const int SIZE = 7000; | ||
| std::string contents = random_string(SIZE); | ||
| std::string filename = "/tmp/foobar-c语言版.txt"; | ||
| assertEquals( 0, cimbare_encode(reinterpret_cast<unsigned char*>(contents.data()), contents.size(), filename.data(), filename.size(), 100) ); | ||
| assertEquals( 0, cimbare_init_encode(filename.data(), filename.size(), 100) ); | ||
| assertEquals( 0, cimbare_encode(reinterpret_cast<unsigned char*>(contents.data()), contents.size()) ); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another usage example. In this case, we encode the whole file at once, as the old api used to require. |
||
|
|
||
| assertEquals( 1, cimbare_next_frame() ); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ var Main = function () { | |
|
|
||
| // cached | ||
| var _idealRatio = 1; | ||
| var _compressBuff = undefined; | ||
|
|
||
| function toggleFullscreen() { | ||
| if (document.fullscreenElement) { | ||
|
|
@@ -19,17 +20,45 @@ var Main = function () { | |
| } | ||
| } | ||
|
|
||
| function importFile(f) { | ||
| const fileReader = new FileReader(); | ||
| fileReader.onload = (event) => { | ||
| const fileData = new Uint8Array(event.target.result); | ||
| Main.encode(f.name, fileData); | ||
| }; | ||
| fileReader.onerror = () => { | ||
| console.error('Unable to read file ' + f.name + '.'); | ||
| function importFile(file) { | ||
| let chunkSize = Module._cimbare_encode_bufsize(); | ||
| if (_compressBuff === undefined) { | ||
| const dataPtr = Module._malloc(chunkSize); | ||
| _compressBuff = new Uint8Array(Module.HEAPU8.buffer, dataPtr, chunkSize); | ||
| } | ||
| let offset = 0; | ||
| let reader = new FileReader(); | ||
|
|
||
| Main.encode_init(file.name); | ||
|
|
||
| reader.onload = function (event) { | ||
| const datalen = event.target.result.byteLength; | ||
| if (datalen > 0) { | ||
| // copy to wasm buff and write | ||
| const uint8View = new Uint8Array(event.target.result); | ||
| _compressBuff.set(uint8View); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reads awkwardly due to JS apis being awkward. But all we're doing here is copying bytes somewhere the wasm code can work with them. |
||
| const buffView = new Uint8Array(Module.HEAPU8.buffer, _compressBuff.byteOffset, datalen); | ||
| Main.encode_bytes(buffView); | ||
|
|
||
| offset += chunkSize; | ||
| readNext(); | ||
| } else { | ||
| // Done reading file | ||
| console.log("Finished reading file."); | ||
|
|
||
| // this null call is functionally a flush() | ||
| // so a no-op, unless it isn't | ||
| const nullBuff = new Uint8Array(Module.HEAPU8.buffer, _compressBuff.byteOffset, 0); | ||
| Main.encode_bytes(nullBuff); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the flush/no-op path for |
||
| } | ||
| }; | ||
|
|
||
| fileReader.readAsArrayBuffer(f); | ||
| function readNext() { | ||
| let slice = file.slice(offset, offset + chunkSize); | ||
| reader.readAsArrayBuffer(slice); | ||
| } | ||
|
|
||
| readNext(); | ||
| } | ||
|
|
||
| function copyToWasmHeap(abuff) { | ||
|
|
@@ -127,22 +156,27 @@ var Main = function () { | |
| invisible_click.style.zoom = canvas.style.zoom; | ||
| }, | ||
|
|
||
| encode: function (filename, data) { | ||
| encode_init: function (filename) { | ||
| console.log("encoding " + filename); | ||
| const wasmData = copyToWasmHeap(data); | ||
| const wasmFn = copyToWasmHeap(new TextEncoder("utf-8").encode(filename)); | ||
|
|
||
| try { | ||
| var res = Module._cimbare_encode(wasmData.byteOffset, wasmData.length, wasmFn.byteOffset, wasmFn.length, -1); | ||
| console.log("encode returned " + res); | ||
| var res = Module._cimbare_init_encode(wasmFn.byteOffset, wasmFn.length, -1); | ||
| console.log("init_encode returned " + res); | ||
| } finally { | ||
| Module._free(wasmData.byteOffset); | ||
| Module._free(wasmFn.byteOffset); | ||
| } | ||
|
|
||
| Main.setTitle(filename); | ||
| Main.setHTML("current-file", filename); | ||
| Main.setActive(true); | ||
| }, | ||
|
|
||
| encode_bytes: function (wasmData) { | ||
| var res = Module._cimbare_encode(wasmData.byteOffset, wasmData.length); | ||
| console.log("encode returned " + res); | ||
|
|
||
| if (res == 0) { | ||
| Main.setActive(true); | ||
| } | ||
| }, | ||
|
|
||
| dragDrop: function (event) { | ||
|
|
@@ -366,4 +400,4 @@ window.addEventListener("drop", function (e) { | |
|
|
||
| window.addEventListener('resize', () => { | ||
| Main.resize(); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example flow.