Skip to content

Commit

Permalink
[emapp] revise capture pass state flow to prevent crash (#42)
Browse files Browse the repository at this point in the history
* [emapp] revise capture pass state flow to prevent crash
* [plugin] fixed a bug plugin_lsmash may not be interruptable
* [emapp] ensure one thread can stop encoder from CapturePassVideoState
  • Loading branch information
hkrn authored Sep 14, 2021
1 parent baae226 commit 4f7d540
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 130 deletions.
1 change: 1 addition & 0 deletions docs/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
* ダイアログ表示中に保存処理が行われた場合は進捗画面が表示されますが何もしません(本来行われてはいけないため)

* エフェクト利用時の画像のミップマップ生成数のミスにより落ちることがある
* ``plugin_lsmash`` を使って動画出力時にキャンセルすると強制終了以外に終了させることができなくなることがある

33.3.0 (2021/8/31)
******************************************
Expand Down
1 change: 1 addition & 0 deletions emapp/include/emapp/BaseApplicationService.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ class BaseApplicationService : private NonCopyable {
static void writeRedoMessage(Nanoem__Application__Command *command, Project *project, Error &error);
static void performRedo(undo_command_t *commandPtr, undo_stack_t *stack, undo_command_t *&commandPtrRef);

void destroyCapturePassState(Project *project);
void setMorphWeight(float value, Project *project);
void sendSaveFileMessage(const URI &fileURI, uint32_t type, uint64_t interval, bool succeeded);
void sendQueryEventMessage(Nanoem__Application__Event *event, const Nanoem__Application__Command *command);
Expand Down
22 changes: 22 additions & 0 deletions emapp/include/emapp/internal/CapturingPassState.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "emapp/Project.h"
#include "emapp/URI.h"

#include "bx/mutex.h"

namespace nanoem {

class BaseApplicationService;
Expand Down Expand Up @@ -87,14 +89,33 @@ class CapturingPassState : private NonCopyable {

bool prepareCapturingViewport(Project *project);
void readPassImage();
void blitOutputPass();
void incrementAsyncCount();
void decrementAsyncCount();
bool canBlitTransition();
virtual void destroy();

StateController *stateController();
const ByteArray &frameImageData() const;
nanoem_u8_t *frameImageDataPtr();
sg_image_desc outputImageDescription() const;
StateTransition stateTransition();
void setStateTransition(StateTransition value);
sg_pass outputPass() const;
sg_buffer frameStagingBuffer() const;
nanoem_frame_index_t startFrameIndex() const;
nanoem_frame_index_t lastPTS() const;
void setLastPTS(nanoem_frame_index_t value);
bool hasSaveState() const;

private:
URI m_fileURI;
StateController *m_stateControllerPtr;
ImageBlitter *m_blitter;
Project *m_project;
Project::SaveState *m_saveState;
StateTransition m_state;
bx::Mutex m_mutex;
ByteArray m_frameImageData;
sg_buffer m_frameStagingBuffer;
Vector2UI16 m_lastLogicalScaleUniformedViewportImageSize;
Expand All @@ -107,6 +128,7 @@ class CapturingPassState : private NonCopyable {
nanoem_u32_t m_sampleLevel;
nanoem_frame_index_t m_lastPTS;
nanoem_frame_index_t m_startFrameIndex;
volatile int m_asyncCount;
int m_blittedCount;
bool m_viewportAspectRatioEnabled;
bool m_displaySyncDisabled;
Expand Down
20 changes: 11 additions & 9 deletions emapp/plugins/lsmash/lsmash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,16 @@ class LSmashEncodeWorker {
void
waitForCompletion()
{
Packet packet;
packet.m_type = kPacketTypeFinish;
packet.m_currentFrameIndex = 0;
packet.m_data = nullptr;
thread_mutex_lock(&m_mutex);
m_packets.push_back(packet);
thread_mutex_unlock(&m_mutex);
thread_signal_wait(&m_signal, THREAD_SIGNAL_WAIT_INFINITE);
if (m_running) {
Packet packet;
packet.m_type = kPacketTypeFinish;
packet.m_currentFrameIndex = 0;
packet.m_data = nullptr;
thread_mutex_lock(&m_mutex);
m_packets.push_back(packet);
thread_mutex_unlock(&m_mutex);
thread_signal_wait(&m_signal, THREAD_SIGNAL_WAIT_INFINITE);
}
}

private:
Expand Down Expand Up @@ -205,7 +207,7 @@ class LSmashEncodeWorker {
nanoem_u32_t m_videoTrackID;
nanoem_u32_t m_audioSummaryIndex;
nanoem_u32_t m_videoSummaryIndex;
bool m_running;
volatile bool m_running;
};

struct LSmashEncoder {
Expand Down
52 changes: 29 additions & 23 deletions emapp/src/BaseApplicationService.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1694,9 +1694,7 @@ BaseApplicationService::destroy()
{
SG_PUSH_GROUP("BaseApplication::destroy");
if (m_capturingPassState) {
while (!m_capturingPassState->transitDestruction(nullptr)) {
}
nanoem_delete_safe(m_capturingPassState);
destroyCapturePassState(nullptr);
}
m_sharedResourceRepository.destroy();
m_window->destroy();
Expand Down Expand Up @@ -3337,9 +3335,10 @@ BaseApplicationService::handleCommandMessage(Nanoem__Application__Command *comma
case NANOEM__APPLICATION__COMMAND__TYPE_EXECUTE_EXPORTING_IMAGE: {
const Nanoem__Application__ExecuteExportingImageCommand *commandPtr = command->execute_exporting_image;
const Nanoem__Application__URI *uri = commandPtr->file_uri;
const URI fileURI(URI::createFromFilePath(uri->absolute_path, uri->fragment));
Project *project = m_stateController->currentProject();
startCapture(project, URI::createFromFilePath(uri->absolute_path, uri->fragment), error);
if (g_sentryAvailable && !error.hasReason()) {
startCapture(project, fileURI, error);
if (g_sentryAvailable && !fileURI.isEmpty() && !error.hasReason()) {
sentry_value_t breadcrumb = sentry_value_new_breadcrumb(nullptr, nullptr);
sentry_value_t data = sentry_value_new_object();
sentry_value_set_by_key(data, "path", g_sentryMaskStringProc(uri->absolute_path));
Expand All @@ -3353,9 +3352,10 @@ BaseApplicationService::handleCommandMessage(Nanoem__Application__Command *comma
case NANOEM__APPLICATION__COMMAND__TYPE_EXECUTE_EXPORTING_VIDEO: {
const Nanoem__Application__ExecuteExportingVideoCommand *commandPtr = command->execute_exporting_video;
const Nanoem__Application__URI *uri = commandPtr->file_uri;
const URI fileURI(URI::createFromFilePath(uri->absolute_path, uri->fragment));
Project *project = m_stateController->currentProject();
startCapture(project, URI::createFromFilePath(uri->absolute_path, uri->fragment), error);
if (g_sentryAvailable && !error.hasReason()) {
startCapture(project, fileURI, error);
if (g_sentryAvailable && !fileURI.isEmpty() && !error.hasReason()) {
sentry_value_t breadcrumb = sentry_value_new_breadcrumb(nullptr, nullptr);
sentry_value_t data = sentry_value_new_object();
sentry_value_set_by_key(data, "path", g_sentryMaskStringProc(uri->absolute_path));
Expand Down Expand Up @@ -5314,32 +5314,30 @@ BaseApplicationService::packEventMessage(const Nanoem__Application__Event *event
void
BaseApplicationService::startCapture(Project *project, const URI &fileURI, Error &error)
{
if (project && m_capturingPassState && !fileURI.isEmpty()) {
m_capturingPassState->setFileURI(fileURI);
m_capturingPassState->save(project);
if (m_capturingPassState->start(error)) {
addModalDialog(m_capturingPassState->createDialog());
project->eventPublisher()->publishPlayEvent(project->duration(), 0);
if (m_capturingPassState) {
if (!fileURI.isEmpty()) {
m_capturingPassState->setFileURI(fileURI);
m_capturingPassState->save(project);
if (m_capturingPassState->start(error)) {
addModalDialog(m_capturingPassState->createDialog());
project->eventPublisher()->publishPlayEvent(project->duration(), 0);
}
else {
stopCapture(project);
error.addModalDialog(this);
}
}
else {
stopCapture(project);
error.addModalDialog(this);
destroyCapturePassState(project);
}
}
else {
internal::CapturingPassState *state = m_capturingPassState;
m_capturingPassState = nullptr;
nanoem_delete(state);
}
}

void
BaseApplicationService::stopCapture(Project *project)
{
if (m_capturingPassState) {
if (m_capturingPassState->transitDestruction(project)) {
nanoem_delete_safe(m_capturingPassState);
}
destroyCapturePassState(project);
if (project) {
project->eventPublisher()->publishStopEvent(project->duration(), 0);
}
Expand Down Expand Up @@ -5730,6 +5728,14 @@ BaseApplicationService::performRedo(undo_command_t *commandPtr, undo_stack_t *st
commandPtrRef = commandPtr;
}

void
BaseApplicationService::destroyCapturePassState(Project *project)
{
while (!m_capturingPassState->transitDestruction(project)) {
}
nanoem_delete_safe(m_capturingPassState);
}

void
BaseApplicationService::setMorphWeight(float value, Project *project)
{
Expand Down
Loading

0 comments on commit 4f7d540

Please sign in to comment.