2.4 KiB
2.4 KiB
MediaCodec Recreation Issue Analysis
Why MediaCodec Recreation is Needed
Problem
MediaCodec is initially configured with surface=nullptr (CPU mode), but later we need it to output to ImageReader surface (GPU mode) when Vulkan device is registered.
Android MediaCodec Limitation
AMediaCodec_setOutputSurface() API has limitations:
- Only works for video tunneling mode
- Does NOT work reliably with async mode callbacks
- Cannot change surface after codec is started in async mode
Current Flow
Initialize()creates MediaCodec with surface=nullptr- MediaCodec starts with async callbacks
SetVulkanDevice()is called later- ImageReader surface is created
- Need to switch MediaCodec output to ImageReader surface
- setOutputSurface() doesn't work in async mode → Must recreate codec
Current Issue After Recreation
Even after recreation, getInputBuffer() returns null for buffer indices from callbacks.
Root Cause
Race condition after AMediaCodec_start():
- Callbacks fire immediately when codec starts
- Buffer indices are enqueued (0-9)
- BUT codec internal buffer allocation isn't complete yet
- When
getInputBuffer()is called with these indices → returns null
Evidence from Logs
23:32:11.938 - Codec started, callbacks fire (indices 0-9 queued)
23:32:12.142 - DecodeFrameAsync gets index 0
23:32:12.142 - getInputBuffer(index=0) → returns null!
Possible Solutions
Option 1: Wait after start() then clear queue
After AMediaCodec_start(), wait 10-50ms for codec to stabilize, then clear old indices and wait for new callbacks.
Option 2: Retry logic
If getInputBuffer() returns null, put index back in queue and retry with next index.
Option 3: Don't recreate - use software decode path
Accept that async mode with surface switching doesn't work well, fall back to CPU decoding.
Option 4: Change initialization order (BEST)
- Call
SetVulkanDevice()BEFOREInitialize() - But this requires changing application code
Recommendation
Try Option 1 first - it's the simplest fix:
// After AMediaCodec_start()
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// Clear old buffer indices
{
std::lock_guard<std::mutex> lock(m_async_handler->m_async_mutex);
while (!m_async_handler->m_async_input_buffer_queue.empty()) {
m_async_handler->m_async_input_buffer_queue.pop();
}
}
// Wait for new callbacks with valid buffers