Skip to content
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

0.3.0 API #10

Closed
wants to merge 40 commits into from
Closed

0.3.0 API #10

wants to merge 40 commits into from

Conversation

jballanc
Copy link
Contributor

@jballanc jballanc commented Dec 2, 2016

Updated API for v0.3.0 that allows for efficient single-call decode of byte arrays or files to either a pre-allocated ByteBuffer or returned as a byte array.

chris-allan and others added 8 commits November 18, 2016 16:48
The file pointer needs to be reset before initializing the stream. Before this
fix, compiling with `DEBUG=1` would lead to a crash on any attempt to transcode
files.
With the v0.3.0 API changes, we seem to be hitting the limits of how many
directly allocated `ByteBuffer`s one can work with in a single JVM. This moves
the largest file first in the test sequence so we can deal with allocation
issues sooner.
They eat up memory and make everything sad...
@chris-allan
Copy link
Member

@melissalinkert should have a look at see what she thinks of the new API. Is there a particular reason the ByteBuffer tests were disabled in dcf512a, @jballanc?

@jballanc
Copy link
Contributor Author

jballanc commented Dec 5, 2016

Yes, ByteBuffer tests were failing due to the issues we saw before with creating too many ByteBuffers. I suspect this may have to do with the changes to getImageMetadata, i.e. there's twice the number of ByteBuffers in play because we're no longer assigning the ByteBuffer to an instance and re-using it, but rather passing it as a parameter.

One option would be to change the API specifically for ByteBuffers such that we can instantiate DecodeContext with a ByteBuffer and re-use it, but then the API for ByteBuffer would be different than for File or byte[] which seems less than idea.

I asked @melissalinkert if support for ByteBuffers was critical, and she indicated it was not, so I had intended to simply remove those bits and simplify the API. Working on a proposal for than in a branch of this branch.

Assert.assertEquals(md5, md5(destination));
}

/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a TestNG annotation here and comment as disabled for now or adjust the test cases to re-use a ByteBuffer if it's a memory issue we're running into.

@@ -3,6 +3,19 @@

<suite name="ome.jxrlib">

<test name="FL_3channel_noZ_compression_lossless">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason this was moved up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the largest of the test files, so moving it was moved up in the hope that (combined with the buffer reallocation workaround in e29028c) running it first would avoid the issues with ByteBuffers. (This worked on my machine, but apparently not on Travis.)

@chris-allan
Copy link
Member

I can't see a reason not to just make it work by adjusting the test cases. We know the size of the required buffers as well based on the test case fixture data being passed in and we can pre-allocate, pass in and/or reuse the buffer as required by setting the TestNG scope.

@jballanc
Copy link
Contributor Author

jballanc commented Dec 7, 2016

We could certainly re-jigger the tests to avoid excessive ByteBuffer allocation. I already attempted a janky solution along these lines in e29028c, but apparently to no avail. If keeping the ByteBuffer APIs around is a priority, I can look at this again, but my impression was that those APIs were work-arounds until direct decoding of byte[] was possible (which it is now), and so they aren't really needed any longer.

Or, rather, it's not necessary to use ByteBuffers with DecodeContext. We could certainly keep the ByteBuffer API in ImageDecode and CodecFactory, if desired, for those that want to separate ImageDecode creation and image decoding. In that case, though, we should write tests that exercise those APIs directly (and avoid more ByteBuffers than necessary).

@chris-allan
Copy link
Member

They're not really a work around but rather an alternative.

The first thing I would try to allocate the buffers ahead of time in the test case itself and utilise TestNG scoping to ensure that they are not destroyed.

jballanc and others added 10 commits January 5, 2017 10:02
This commit includes the Doxygen configuration, a `make` target to generate
docs, and documentation for most of the classes.
This commit includes documentation comments for `ImageEncoder`, `ImageMetadata`,
`Resolution`, and `Stream`.
For whatever reason it seems that passing object references causes crashes when
using Java `ByteBuffer`s to pass image data. Reverting this back to pass
pointers.
@chris-allan
Copy link
Member

Two things, @jballanc:

  • Lets get some test cases added for decoding into a larger ByteBuffer at a given offset
  • We should probably have getImageMetadata(ByteBuffer source) added to the API and tests added for it

@melissalinkert
Copy link
Member

Java API looks good in general. I could see it being useful to have something like AbstractDecode.decodeFrame(int frame, byte[] source, int sourceOffset, int sourceLength, byte[] destination, int destinationOffset), especially for consistency with the other decodeFrame signatures that take a File or ByteBuffer. It might also be helpful to have place-holder getFrameCount methods that just returns 1 - we know that there is only one frame in practice, but that won't be obvious to anyone external. Adding a frame count field to ImageMetadata would also work, if that's easier.

Otherwise, I think it would be good to do a little more bounds checking in the decodeFrame methods, to ensure that the frame and offset are non-negative and the length is positive.

This is the first step of refactoring the C++ and Java APIs so that they are
more consistent. On the C++ side, input buffers are always `unsigned char` and
instead of multiple overloads, optional offsets are represented as optional
parameters. This does necessitate rearranging parameter order on some methods,
so all methods were re-arranged so that offsets and lengths appear at the end of
the parameter list.

On the Java side, instead of relying on the built-in SWIG mechanisms for passing
NIO Buffers and `byte[]` across the JNI bridge, we have copied the definitions
into our `JXR.i` definitions and changed the `byte[]` implementation to pass
across as `unsigned char *`. This allows us to use the same C++ methods for
both, though due to limitations with SWIG auto-generation, we need to use the
`%rename` directive to prevent definitions from replacing each other. This
results in a new set of more descriptive method names.
This change brings the header doc comments back in line with the actual
parameter lists for DecodeContext's methods that were changed in the last commit.
With this set of changes, we should have the final version of the API that we
want for AbstractDecode, including congruent methods to decode either `byte[]`s
or `ByteBuffer`s with an offset and length.
These methods gave the API just a bit *too much* surface area. For now, if a
user needs a `byte[]` from the decoded image, they can use the methods that
return `byte[]` and if they need to write into an array at an offset they can
use the methods that write to `ByteBuffer`s. (Really, we just don't have
sufficient testing around passing `byte[]`s across the SWIG/JNI bridge as out
parameters.)
With the finished `AbstractDecode`/`Decode` API, we no longer need mappings to
the lower-level C++ APIs. Not to mention that, due to issues with pointer
lifetimes, we cannot guarantee their use from Java is safe.
@melissalinkert
Copy link
Member

Closing as discussed in the context of upcoming work on #32.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants