From 90d273c8e6a1e9835dcb2b5f7c2162006801f803 Mon Sep 17 00:00:00 2001 From: ened Date: Wed, 15 Oct 2025 02:25:11 +0900 Subject: [PATCH] WIP --- .../src/Decoder/MediaCodecAsyncHandler.cpp | 6 +- .../src/Decoder/MediaCodecSurfaceManager.cpp | 88 +++---------------- .../src/Decoder/MediaCodecSurfaceManager.h | 6 +- 3 files changed, 20 insertions(+), 80 deletions(-) diff --git a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecAsyncHandler.cpp b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecAsyncHandler.cpp index e8251f9..0c9e47e 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecAsyncHandler.cpp +++ b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecAsyncHandler.cpp @@ -464,10 +464,14 @@ bool MediaCodecAsyncHandler::ProcessAsyncOutputFrame(int32_t output_index, AMedi // Step 1: Release MediaCodec buffer to ImageReader surface (render=true) // This triggers MediaCodec to render the frame to ImageReader's Surface LogInfo("ProcessAsyncOutputFrame: Releasing output buffer to ImageReader (render=true)..."); + LogInfo("ProcessAsyncOutputFrame: About to call releaseOutputBuffer with index=" + + std::to_string(output_index) + ", codec=0x" + + std::to_string(reinterpret_cast(m_codec))); media_status_t status = AMediaCodec_releaseOutputBuffer(m_codec, output_index, true); - LogInfo("ProcessAsyncOutputFrame: releaseOutputBuffer returned status=" + std::to_string(status)); + LogInfo("ProcessAsyncOutputFrame: releaseOutputBuffer COMPLETED with status=" + + std::to_string(status) + " (0=AMEDIA_OK)"); if (status != AMEDIA_OK) { LogError("ProcessAsyncOutputFrame: Failed to release output buffer: " + std::to_string(status)); diff --git a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.cpp b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.cpp index 776bbb1..e2ee033 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.cpp +++ b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.cpp @@ -38,8 +38,6 @@ MediaCodecSurfaceManager::MediaCodecSurfaceManager() , m_video_height(0) , m_java_vm(nullptr) , m_jni_env(nullptr) - , m_looper_running(false) - , m_looper(nullptr) , m_initialized(false) { } @@ -526,73 +524,28 @@ bool MediaCodecSurfaceManager::SetupImageReader(uint32_t width, uint32_t height) LogInfo("AImageReader created successfully (format=PRIVATE, maxImages=3)"); - // CRITICAL FIX: AImageReader callbacks require ALooper to dispatch events - // Android NDK AImageReader_setImageListener uses the calling thread's Looper - // If no Looper exists, callbacks are never invoked! - // Solution: Create dedicated handler thread with Looper + // CRITICAL: Android NDK AImageReader callbacks are invoked on a dedicated internal thread + // managed by the system - NO Looper or Handler thread is required! + // The listener can be set from any thread, and callbacks will be dispatched automatically. + // Reference: https://developer.android.com/ndk/reference/group/media#aimagereader_setimagelist - LogInfo("Starting handler thread with ALooper for ImageReader callbacks..."); + LogInfo("Setting native image listener (callback dispatched on system thread)..."); - // Start looper thread - m_looper_running = true; - m_looper_thread = std::thread([this]() { - // Prepare Looper on this thread (required for AImageReader callbacks!) - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - if (!looper) { - LogError("Handler thread: Failed to prepare ALooper"); - m_looper_running = false; - return; - } + // Set native image listener (NO JAVA, NO LOOPER NEEDED!) + AImageReader_ImageListener listener{ + .context = this, + .onImageAvailable = OnImageAvailableStatic + }; - m_looper = looper; - LogInfo("Handler thread: ALooper prepared successfully"); - - // Register image listener on THIS thread (with Looper) - AImageReader_ImageListener listener{ - .context = this, - .onImageAvailable = OnImageAvailableStatic - }; - - media_status_t status = AImageReader_setImageListener(m_image_reader, &listener); - if (status != AMEDIA_OK) { - LogError("Handler thread: Failed to set image listener: " + std::to_string(status)); - m_looper_running = false; - return; - } - - LogInfo("Handler thread: Native image listener registered (callback: OnImageAvailableStatic)"); - - // Run Looper event loop (blocks until m_looper_running = false) - LogInfo("Handler thread: Starting Looper event loop..."); - while (m_looper_running) { - // Poll for events with 100ms timeout - // This allows callbacks to be dispatched while checking m_looper_running periodically - int result = ALooper_pollAll(100, nullptr, nullptr, nullptr); - // result: ALOOPER_POLL_WAKE (-1), ALOOPER_POLL_CALLBACK (-2), - // ALOOPER_POLL_TIMEOUT (-3), ALOOPER_POLL_ERROR (-4), or >= 0 (fd) - if (result == ALOOPER_POLL_ERROR) { - LogError("Handler thread: ALooper_pollAll error"); - break; - } - } - - LogInfo("Handler thread: Looper event loop exited"); - }); - - // Wait briefly for thread to initialize - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - - if (!m_looper_running) { - LogError("Handler thread failed to start"); - if (m_looper_thread.joinable()) { - m_looper_thread.join(); - } + status = AImageReader_setImageListener(m_image_reader, &listener); + if (status != AMEDIA_OK) { + LogError("Failed to set image listener: " + std::to_string(status)); AImageReader_delete(m_image_reader); m_image_reader = nullptr; return false; } - LogInfo("Handler thread started successfully with Looper"); + LogInfo("Native image listener registered (callback: OnImageAvailableStatic)"); // Get ANativeWindow from AImageReader (NO JAVA!) ANativeWindow* nativeWindow = nullptr; @@ -1052,19 +1005,6 @@ JNIEnv* MediaCodecSurfaceManager::GetJNIEnv() const { void MediaCodecSurfaceManager::CleanupJNI() { // PHASE 2: Native AImageReader cleanup (replaces JNI DeleteGlobalRef) - // Stop looper thread before cleaning up ImageReader - if (m_looper_running) { - LogInfo("Stopping handler thread..."); - m_looper_running = false; - - if (m_looper_thread.joinable()) { - m_looper_thread.join(); - LogInfo("Handler thread joined successfully"); - } - - m_looper = nullptr; - } - // Release current image before cleaning up ImageReader if (m_current_image) { ReleaseImage(); diff --git a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.h b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.h index c13baec..b13eb08 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.h +++ b/vav2/platforms/windows/vavcore/src/Decoder/MediaCodecSurfaceManager.h @@ -165,15 +165,11 @@ private: JNIEnv* m_jni_env; // Synchronization for OnImageAvailableCallback (Phase 2) + // AImageReader callbacks are dispatched on system-managed thread automatically mutable std::mutex m_image_mutex; std::condition_variable m_image_cv; std::atomic m_image_available{false}; - // Handler thread for AImageReader callbacks (Looper required) - std::thread m_looper_thread; - std::atomic m_looper_running{false}; - void* m_looper; // ALooper* (opaque pointer to avoid header dependency) - // Initialization state bool m_initialized; };