From 0f4bdb7f4e26eb124c071f78201b86e81393b123 Mon Sep 17 00:00:00 2001 From: "hkrn (a.k.a shimacpyon)" <129939+hkrn@users.noreply.github.com> Date: Wed, 15 Sep 2021 23:36:36 +0900 Subject: [PATCH] [emapp] more video encoder fixes (#43) * [plugin] fixed a thread leak detected by TSAN * [emapp] ensure async frame reader works only one session --- .../emapp/internal/CapturingPassState.h | 3 +- emapp/plugins/lsmash/lsmash.cc | 6 ++- emapp/src/internal/CapturingPassState.cc | 37 ++++++++++++------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/emapp/include/emapp/internal/CapturingPassState.h b/emapp/include/emapp/internal/CapturingPassState.h index 2a5ffbd2..adc15319 100644 --- a/emapp/include/emapp/internal/CapturingPassState.h +++ b/emapp/include/emapp/internal/CapturingPassState.h @@ -97,7 +97,8 @@ class CapturingPassState : private NonCopyable { StateController *stateController(); const ByteArray &frameImageData() const; - nanoem_u8_t *frameImageDataPtr(); + nanoem_u8_t *mutableFrameImageDataPtr(); + bx::Mutex &mutex(); sg_image_desc outputImageDescription() const; StateTransition stateTransition(); void setStateTransition(StateTransition value); diff --git a/emapp/plugins/lsmash/lsmash.cc b/emapp/plugins/lsmash/lsmash.cc index e57f906a..3c0c5151 100644 --- a/emapp/plugins/lsmash/lsmash.cc +++ b/emapp/plugins/lsmash/lsmash.cc @@ -397,7 +397,11 @@ struct LSmashEncoder { { int result = 0; if (m_root) { - m_worker->waitForCompletion(); + if (m_worker) { + m_worker->waitForCompletion(); + delete m_worker; + m_worker = nullptr; + } result = lsmash_close_file(&m_fileParameters); handleStatusCode(result, status); lsmash_cleanup_summary(reinterpret_cast(m_audioSummary)); diff --git a/emapp/src/internal/CapturingPassState.cc b/emapp/src/internal/CapturingPassState.cc index 08b85b3a..571ed5d7 100644 --- a/emapp/src/internal/CapturingPassState.cc +++ b/emapp/src/internal/CapturingPassState.cc @@ -1107,11 +1107,17 @@ CapturingPassState::frameImageData() const } nanoem_u8_t * -CapturingPassState::frameImageDataPtr() +CapturingPassState::mutableFrameImageDataPtr() { return m_frameImageData.data(); } +bx::Mutex & +CapturingPassState::mutex() +{ + return m_mutex; +} + sg_image_desc CapturingPassState::outputImageDescription() const { @@ -1251,7 +1257,7 @@ CapturingPassAsImageState::capture(Project *project, Error &error) readPassImage(); ImageWriter writer(fileURI(), error); const nanoem_u32_t width = desc.width, height = desc.height; - writer.write(frameImageDataPtr(), width, height, desc.pixel_format); + writer.write(mutableFrameImageDataPtr(), width, height, desc.pixel_format); state = kFinished; setStateTransition(state); SG_POP_GROUP(); @@ -1496,28 +1502,33 @@ CapturingPassAsVideoState::handleCaptureViaEncoderPlugin(Project *project, nanoe handleReadPassAsync(const void *data, size_t size, void *opaque) { AsyncReadHandler *self = static_cast(opaque); - CapturingPassAsVideoState *state = self->m_state; + self->readPassAsync(data, size); + nanoem_delete(self); + } + void + readPassAsync(const void *data, size_t size) + { + bx::MutexScope scope(m_state->mutex()); Error error; - if (state->frameImageData().size() == size) { - memcpy(state->frameImageDataPtr(), data, size); - if (state->outputImageDescription().pixel_format == SG_PIXELFORMAT_RGBA8) { - nanoem_u32_t *dataPtr = reinterpret_cast(state->frameImageDataPtr()); + if (m_state->frameImageData().size() == size) { + memcpy(m_state->mutableFrameImageDataPtr(), data, size); + if (m_state->outputImageDescription().pixel_format == SG_PIXELFORMAT_RGBA8) { + nanoem_u32_t *dataPtr = reinterpret_cast(m_state->mutableFrameImageDataPtr()); for (size_t i = 0, numPixels = size / sizeof(*dataPtr); i < numPixels; i++) { nanoem_u32_t *ptr = dataPtr + i, v = *ptr; *ptr = 0 | ((v & 0x000000ff) << 16) | (v & 0x0000ff00) | ((v & 0x00ff0000) >> 16) | (v & 0xff000000); } } - if (!state->encodeVideoFrame(state->frameImageData(), self->m_videoFrameIndex, error)) { - state->stopEncoding(error); - state->setStateTransition(kCancelled); + if (!m_state->encodeVideoFrame(m_state->frameImageData(), m_videoFrameIndex, error)) { + m_state->stopEncoding(error); + m_state->setStateTransition(kCancelled); } } else { - state->stopEncoding(error); - state->setStateTransition(kCancelled); + m_state->stopEncoding(error); + m_state->setStateTransition(kCancelled); } - nanoem_delete(self); } CapturingPassAsVideoState *m_state; nanoem_frame_index_t m_videoFrameIndex;