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

Implement async callback for Android mediacodec #4105

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

trengginas
Copy link
Member

@trengginas trengginas commented Oct 14, 2024

This is the current pattern for encoding/decoding using Android media codec:

  1. check the input buffer availability
  2. once an input buffer is available, input the data to encode/decode
  3. check the output buffer availability
  4. once the output buffer is available, it is the encoded/decoded data

Issues related to this pattern/when using polling:

  1. We are using polling when checking the input/output buffer availability. This is necessary because the API won't block to wait for the buffer to be available.
  2. A supply to input buffer doesn't always produce from the output buffer. Sometimes it needs to be fed more than one input buffer before the output is available, so it might waste some polling time/no guarantee of an output.
  3. When the poll returns error, the codec might need to be restarted (ref). However, there are instances where this doesn't resolve the issue, and the codec fails to recover even after being re-created.

This patch will use an async callback to the implementation.

  1. Set new_input_buffer_avail() and new_output_buffer_avail() callback.
  2. The callback will notify the index of the input/output buffer available to use. The buffer information will be stored in an atomic queue.
  3. The encode/decode process will only use the buffer information provided from the callback on the queue.
  4. This will eliminate the polling requirements.

Notes:

  • The patch will use the atomic queue from oboe_dev.cpp
  • The async callback is supported for Android API level 28 and later.
  • There's noticeable lag/delay when using the Android MediaCodec backend. Unfortunately, this patch doesn't address the issue.
  • To completely avoid the lag/delay issue, you can use an alternative video codec backend, such as OpenH264. This solution is also applicable to older devices.

AtomicQueue() {}
};

#endif
Copy link
Member

Choose a reason for hiding this comment

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

  • Headers in include dir are meant to be public API, so by convention it should use a specific prefix such as pj or pjmedia.
  • If this is public API, IMO, the interface better uses C (as used by the rest), e.g: pj_atomic_queue, and perhaps part of PJLIB instead of PJMEDIA, note that the implementation can still use C++.

nanangizz
nanangizz previously approved these changes Oct 15, 2024
pj_atomic_queue() {}
};

#endif
Copy link
Member

Choose a reason for hiding this comment

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

This is definitely still C++ (with C naming style :)
Please check ioqueue_symbian.cpp which use ioqueue.h.


#if defined(PJ_ANDROID) && PJ_ANDROID != 0

//#include <android/log.h>
Copy link
Member

Choose a reason for hiding this comment

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

For tracing purpose, perhaps it can use the usual approach, e.g: using PJLIB log (instead of Android), tracing is by default disabled.

@nanangizz nanangizz self-requested a review October 15, 2024 02:10
@nanangizz nanangizz dismissed their stale review October 15, 2024 02:11

Approving by accident

Comment on lines 30 to 36
/* Atomic queue (ring buffer) for single consumer & single producer.
*
* Producer invokes 'pj_atomic_queue_put(item)' to put an item to the back of
* the queue.
* Consumer invokes 'pj_atomic_queue_get(item)' to get an item from the head of
* the queue.
*/
Copy link
Member

Choose a reason for hiding this comment

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

This does not seem to be part of the docs?
Note that the "single consumer & single producer" condition needs to be explicitly specified in the docs.

PJ_DEF(pj_status_t) pj_atomic_queue_put(pj_atomic_queue_t *atomic_queue,
void *item)
{
PJ_ASSERT_RETURN(atomic_queue && atomic_queue->aQ, PJ_EINVAL);
Copy link
Member

Choose a reason for hiding this comment

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

Check item too?
Also below.

const char* name,
pj_atomic_queue_t **atomic_queue)
{
pj_atomic_queue_t *aqueue;
Copy link
Member

Choose a reason for hiding this comment

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

Add pre-verification/PJ_ASSERT_RETURN()?
Also below.

Copy link
Member

@sauwming sauwming left a comment

Choose a reason for hiding this comment

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

Also add in the PR description as to why this PR is needed, e.g. is there any performance issue with the current polling approach?
If yes, does using atomic queue manage to improve performance/reduce video lags (especially when compared to using other codec backend such as OpenH264)?

PJ_DECL(pj_status_t) pj_atomic_queue_destroy(pj_atomic_queue_t *atomic_queue);

/**
* Put a item to the back of the queue. If the queue is almost full
Copy link
Member

Choose a reason for hiding this comment

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

an item.

What does "almost" full mean?

}

/**
* Get a item from the head of the queue
Copy link
Member

Choose a reason for hiding this comment

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

an item.
Also below.

/* Surpress warning when debugging log is disabled */
PJ_UNUSED_ARG(name_);

// PJ_LOG(5, (name_, "Created AtomicQueue: maxItemCnt=%d itemSize=%d",
Copy link
Member

Choose a reason for hiding this comment

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

Rather than comment it, better disable it as @nanangizz suggested, such as using macro TRACE, so we can easily enable it when logging is needed.

@trengginas
Copy link
Member Author

Also add in the PR description as to why this PR is needed, e.g. is there any performance issue with the current polling approach? If yes, does using atomic queue manage to improve performance/reduce video lags (especially when compared to using other codec backend such as OpenH264)?

Unfortunately, the lag/delay issue still noticeable.
Tested scenario:

  • Using the configuration specified here
  • Using hw codec

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

Successfully merging this pull request may close these issues.

3 participants