Repository navigation
Reduce the CPU usage of the Android encoder - #201
Merged
Merged
Conversation
… while recording Measured on a Galaxy S22 with the default settings, the CPU time added by recording fell from about 307 ms/s to about 255 ms/s. - The outputs of the video and audio encoders are drained on a dedicated thread each, and audio input is fed on a dedicated thread, instead of handing every dequeue to the blocking pool of the executor. Encoded data is copied directly from the direct buffers of MediaCodec rather than through Java arrays. - The Vulkan image, memory, view and framebuffer imported from each hardware buffer of the ImageWriter are cached and reused, instead of being created and destroyed for every frame. - The bindings generated by java_api! cache the class and the method and field IDs and call them without looking them up again.
Each loop is handed to the blocking pool once, so it keeps waiting in MediaCodec itself without a hand-off per dequeue, and its thread returns to the pool when the encoder ends.
ruccho
marked this pull request as ready for review
October 28, 2026 09:41
hkmt-mmy
approved these changes
Oct 29, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a Galaxy S22 with the default options (blit path, in-memory buffer, audio enabled), recording added about 307 ms/s of CPU time to the process. The threads of unienc accounted for about 210 ms/s of that. Profiling with simpleperf showed that the main costs were not the encoder itself:
dequeueOutputBufferanddequeueInputBufferto the blocking pool, which costs a task, a wake-up and a park per call.Change
java_api!cache the class and the method and field IDs in aOnceLockand call them with the unchecked JNI functions.Drop.The C ABI is unchanged. The prebuilt native binaries are not updated in this PR and are to be rebuilt with
build-unienc.yml.Testing
cargo ndk check -p unienc_android_mcpasses without warnings. The 13 tests ofjava_api_macrospass.scripts/android-device-test.sh --releasepasses on a Galaxy S22 (e2eande2e-idr-interval).libunienc_c.soreplaced, alternating two runs of each version:The loops ran on dedicated threads in the first revision of this PR and were then moved to the blocking pool. The measurement was repeated with the three versions, alternating two runs of each. The CPU time of all threads varied from +192 to +317 ms/s between runs and is not compared here.
The process had the same number of threads with both revisions, one more than with main.
Per operation, the following costs were eliminated:
These costs were reduced:
These per-operation values come from a callgraph profile, so their scale differs slightly from the table above. The remaining scheduling cost is mainly from the fence wait of the blit path and the video input, which still use the blocking pool.