ndk icon indicating copy to clipboard operation
ndk copied to clipboard

media_codec: Fix `dequeue_output_buffer` treating some events as error

Open zmerp opened this issue 3 years ago • 18 comments

The MediaCodec wrapper had some issues with handling some non-error results for dequeue_output_buffer. This PR fixes it.

The PR has been tested for the decoder path in soon-to-be-in-production code. I did not experience any unhandleable error originating inside the ndk calls.

Here I used unreachable!() to avoid adding an unused variant in MediaCodecOutputResult and I would like some feedback for a better solution.

zmerp avatar Jul 10 '22 20:07 zmerp

Here I used unreachable!() to avoid adding an unused variant in MediaCodecOutputResult and I would like some feedback for a better solution.

Can you call from_status() unconditionally and match on the Ok(()), Err(ffi::AMEDIACODEC_INFO_TRY_AGAIN_LATER) and Err(_)?

MarijnS95 avatar Jul 10 '22 20:07 MarijnS95

@MarijnS95 The problem is that result is not used in a regular way. AMediaCodec_dequeueOutputBuffer documentation says that 0 or positive values are the buffer index, negative values are error or other non-fatal events. I cannot wrap the result with from_status, first I need to check if the value is a buffer index. But then the Ok(()) value still remains redundant and should never be hit.

zmerp avatar Jul 10 '22 20:07 zmerp

I've replaced .map(|()| unreachable!()) with the more idiomatic Err([...].unwrap_err())

zmerp avatar Jul 10 '22 21:07 zmerp

The MediaCodec API in ndk v0.7 is flat out broken without this PR.

zmerp avatar Aug 27 '22 10:08 zmerp

@MarijnS95 ping, I'm using my branch in production and it works, I think this PR can be merged.

zmerp avatar Sep 06 '22 18:09 zmerp

@zarik5 This patch simply fails to explain why the caller can't match on the Err results from these functions, it seems there's nothing wrong with the current implementation hence this PR isn't "fixing" anything?

MarijnS95 avatar Sep 07 '22 21:09 MarijnS95

@MarijnS95 I see this is a matter of convention. I think AMEDIACODEC_INFO_* events should be not considered as error, in fact there is “INFO” in the name. Furthermore AMEDIACODEC_INFO_* event are not “universal” media_status_t errors, the meaning of these events represented by low magnitude negative integers seems specific to the AMediaCodec_dequeueOutputBuffer call.

zmerp avatar Sep 08 '22 00:09 zmerp

Any documentation we can quote that states that these functions return both AMEDIACODEC_INFO_* or any of the AMEDIA_* error values?

Regardless, I'd rather see anything that doesn't return an OutputBuffer to be treated as an Err. Perhaps your MediaCodecOutputResult can instead wrap NdkMediaError? Maybe give input buffers the same treatment. Not sure what the best way forward is here, except that the current implementation looks messy and inconsistent.

MarijnS95 avatar Sep 08 '22 09:09 MarijnS95

Nevertheless, don't forget to document this problem and API change in the changelog.

MarijnS95 avatar Sep 08 '22 09:09 MarijnS95

@MarijnS95 I looked in the source code and it's not completely clear what to do either https://android.googlesource.com/platform/frameworks/av/+/master/media/ndk/NdkMediaCodec.cpp#693 . I tried another opinionated solution. In any case I fixed also a "real" bug, the AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE and AMEDIACODEC_ERROR_RECLAIMED error were recognized as a buffer index. I changed the check from "res >= 0" to "0 <= res < 1000"

zmerp avatar Sep 08 '22 11:09 zmerp

In any case I fixed also a "real" bug, the AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE and AMEDIACODEC_ERROR_RECLAIMED error were recognized as a buffer index. I changed the check from "res >= 0" to "0 <= res < 1000"

That's absolutely horrible, is there any documentation stating the highest buffer index being used? Or is it just these two loose positive values?

If you can't find anything I'll ping some NDK contacts to see what's up here.

MarijnS95 avatar Sep 08 '22 12:09 MarijnS95

@MarijnS95 I didn't find any information about a "minimum error code integer" or "maximum buffer index". The "1000" cut point was completely arbitrary on my side.

zmerp avatar Sep 08 '22 12:09 zmerp

AMediaCodec_dequeueInputBuffer can indeed return AMEDIACODEC_INFO_TRY_AGAIN_LATER. I fixed it.

zmerp avatar Sep 11 '22 21:09 zmerp

@MarijnS95 I didn't find any information about a "minimum error code integer" or "maximum buffer index". The "1000" cut point was completely arbitrary on my side.

Anything we can do about this? Otherwise I'd recommend purely parsing the two positive error codes and considering any other positive number as a valid buffer index.

https://github.com/rust-windowing/android-ndk-rs/blob/25e647abe800d08453b74c3a1fa90528ff97844c/ndk-sys/src/ffi_aarch64.rs#L14563-L14568

MarijnS95 avatar Sep 14 '22 17:09 MarijnS95

Otherwise can you inquire about this over at https://github.com/android/ndk?

MarijnS95 avatar Sep 14 '22 17:09 MarijnS95

Anything we can do about this? Otherwise I'd recommend purely parsing the two positive error codes and considering any other positive number as a valid buffer index.

Not a good idea to me, it might break in a new API level.

Otherwise can you inquire about this over at https://github.com/android/ndk?

Sure.

zmerp avatar Sep 14 '22 17:09 zmerp

Not a good idea to me, it might break in a new API level.

It is already broken by design unless there's a maximum buffer index.

MarijnS95 avatar Sep 14 '22 17:09 MarijnS95

Otherwise can you inquire about this over at https://github.com/android/ndk?

Here you go: https://github.com/android/ndk/discussions/1768

zmerp avatar Sep 14 '22 18:09 zmerp

This is blocked on filing an upstream bug report to figure out what to do with the broken return codes.

MarijnS95 avatar Oct 25 '22 12:10 MarijnS95

Looks like you bumped the issue today @zarik5, unfortunate to see that upstream hasn't provided any clarification thus far :(

MarijnS95 avatar Dec 21 '22 20:12 MarijnS95

Given no feedback upstream, should we merge this PR with my assumption of 1000 as an absolute value cutting point? I think It's reasonable, because how C APIs normally evolve. Usually error codes get added with increasing magnitude, maybe sometimes skipping tens or hundreds to reserve slots to more neatly group errors by scope, but almost never going under the lowest initial error value (in absolute terms). As for testing, I've been using this PR in production for a while now.

zmerp avatar Dec 21 '22 20:12 zmerp

In its current form this PR proposes a breaking change, merging it would mean forcing the release of ndk 0.8.0 and the entire ecosystem propagation mess with it whenever we want to release an ndk update for this or other means.

Rather we accept that this API was fundamentally broken and Deal With It™ until the next sensible opportunity to correct it. Users can currently work around this by manually matching these "error-like" values out of index anyway.

One thing you could do is return these codes in Err(NdkMediaError::UnknownResult(...)) which would not break the API, though we cannot extend MediaErrorResult as it has never been marked #[non_exhaustive] making it equally inconvenient for users to figure out what they have to do. However, I'd like to sanity-check that with a second opinion from someone else who uses the media codec API to prevent this whole "oh we discovered the API doesn't represent important thing X" situation within a month after release again.

MarijnS95 avatar Dec 21 '22 21:12 MarijnS95

Correct me if I'm wrong, but if a certain API is completely broken, it's ok to fix it with a patch release (-.-.X) even if the API surface changes in a breaking way (it's a bug fix). I imagine noone in the wild is doing what you propose right now, instead if they are interested in the Mediacodec API they are probably using my PR.

zmerp avatar Dec 21 '22 22:12 zmerp

If it goes paired with a yank of the broken release, within a day of releasing, maybe? At this point you can't assume no-one is using MediaCodec, and you can't stop their project from compiling by publishing a semver-breaking release without bumping semver.

MarijnS95 avatar Dec 21 '22 22:12 MarijnS95

I'm not gonna debate further. I'll will continue using my fork for production, I hope this PR will land sometimes. Maybe add it to a 0.8 tag as a reminder?

zmerp avatar Dec 21 '22 22:12 zmerp

Nothing to debate, circumventing semver is simply not done.

Proposing another alternative: new unbroken functions with a different name, and #[deprecate] the broken ones (without duplicating all code)?

MarijnS95 avatar Dec 21 '22 22:12 MarijnS95

Proposing another alternative: new unbroken functions with a different name, and #[deprecate] the broken ones (without duplicating all code)?

No reason messing with it IMO. Let's merge this PR once you are ready to release v0.8.

zmerp avatar Dec 21 '22 23:12 zmerp

If a new release of ndk is imminent, please consider merging this PR.

zmerp avatar Mar 08 '23 19:03 zmerp

@zarik5 as said before, only if it were a semver-breaking release.

MarijnS95 avatar Mar 08 '23 20:03 MarijnS95

I saw that the MSRV got bumped, this is a breaking change.

zmerp avatar Mar 08 '23 23:03 zmerp