Skip to content

Conversation

@leo030303
Copy link
Contributor

@leo030303 leo030303 commented Jul 6, 2025

I've copy pasted the PR from #1362 and updated it with some of the suggestions made on that pull request. The main changes are:

  • Have all the public-facing Rust API code in its own file.
  • Used some enums from rav1d instead of redefining new ones, and added in doc comments from the original dav1d-rs library to a few items.
  • Removed as much unsafe code as I could and replaced it with the Rust methods from rav1d as much as possible.

It currently works as a drop-in replacement for dav1d-rs; adding in use rav1d as dav1d; to my fork of image makes everything work fine.

The only functional changes I made are I removed the unsafe impls of Send and Sync for InnerPicture so Picture is no longer Sync or Send. I looked through the code and I don't believe DisjointMut<Rav1dPictureDataComponentInner>, which is a field of one of its children, is thread safe, though I'm open to correction there; I'm pretty unfamiliar with unsafe Rust.

I also don't have safety comments on the two unsafe blocks in rust_api.rs; I'm unsure what these would look like, so open to suggestions there. These are mostly taken verbatim from the old pull request.

Copy link
Collaborator

@kkysen kkysen left a comment

Choose a reason for hiding this comment

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

Thanks for the much safer implementation! I'm still taking a closer look at the unsafes, as the few remaining are still quite critical, but I wanted to give some initial feedback in general first.

@kkysen kkysen changed the title Implement Rust API Implement dav1d-rs's Rust API Jul 7, 2025
kkysen added a commit that referenced this pull request Jul 7, 2025
Pulled out the docs additions from #1439 into its own PR.
@leo030303 leo030303 requested a review from kkysen July 8, 2025 22:23
kkysen added a commit that referenced this pull request Jul 15, 2025
…1442)

Pulled out the `Rav1dError` changes from #1439 into a separate PR.
kkysen added a commit that referenced this pull request Jul 15, 2025
…e `u32` (#1443)

Pulled out type changes from here #1439 into its own PR.
Copy link
Collaborator

@kkysen kkysen left a comment

Choose a reason for hiding this comment

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

@leo030303, could you rebase this on main? There are a lot of other commits in here now, so it's harder to review.

@leo030303 leo030303 requested a review from kkysen July 20, 2025 13:49
@leo030303 leo030303 requested a review from kkysen July 24, 2025 18:59
@leo030303 leo030303 requested a review from kkysen July 28, 2025 17:28
@leo030303
Copy link
Contributor Author

I think the core of this PR, the rust API, seems to be in a good place, for the work aligning the implementation closer to the spec I think it makes sense to do those under separate PR's, but overall I think the rust API should be good to merge if it all looks fine from your end

@leo030303
Copy link
Contributor Author

leo030303 commented Aug 16, 2025

I think this was closed accidentally?
@kkysen

@kkysen
Copy link
Collaborator

kkysen commented Aug 17, 2025

I think this was closed accidentally? @kkysen

Oh, whoops, I didn't realize "fix" expressions for a PR comment close them. I thought it only worked on issues.

@kkysen kkysen reopened this Aug 17, 2025
@Shnatsel
Copy link

Shnatsel commented Sep 2, 2025

Is there anything blocking this? I'd love to see this merged and published so we could drop the last remaining C library, dav1d, from the image crate.

@leo030303
Copy link
Contributor Author

Is there anything stopping this from being merged? Happy to make any requested changes @kkysen

unsafe {
slice::from_raw_parts(
self.0.plane_data_ptr(self.1) as *const u8,
(stride * height) as usize,
Copy link
Contributor

Choose a reason for hiding this comment

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

Casting after the multiplication is a bit suspicious. These are u32 where stride in particular came from a ptrdiff_t downcast to a u32 with try_into().unwrap() in Picture::stride. This will overflow for larger images. Of course that's never a memory safety problem, it will just make the returned buffer smaller.

let height = match component {
PlanarImageComponent::Y => self.height(),
_ => match self.pixel_layout() {
PixelLayout::I420 => (self.height() + 1) / 2,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
PixelLayout::I420 => (self.height() + 1) / 2,
PixelLayout::I420 => self.height().div_ceil(2),

Handles the case where height = u32::MAX correctly, too.

impl AsRef<[u8]> for Plane {
fn as_ref(&self) -> &[u8] {
let (stride, height) = self.0.plane_data_geometry(self.1);
// SAFETY: both stride and height can't be negative, the `stride` and `height` methods panic if they are so there's no undefined behaviour
Copy link
Contributor

Choose a reason for hiding this comment

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

The wording here misses the mark and ends in a non-sequitur. It should justify why the extent is correct for the pointer that's used but only justifies how the inputs are somehow bounded in [0; u32::MAX) (repeating the type explicitly would also help readability).

Does Rav1dPictureDataComponent uphold that invariant properly? For instance there's a Rav1dPictureDataComponent::wrap_buf constructor which takes an arbitrary, unverified stride and Rav1dPictureData::data and Rav1dPicture::data are indeed a public attributes so that is non-obvious by itself. The invariant has to be protected by Picture and its only constructor path Decoder::get_picture but I don't seem exactly how, and that comment is certainly way to little to prove it.

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.

Provide Rust API

4 participants