Skip to content

Commit f1b55c6

Browse files
committed
fix(encoder): stop async worker before codec access in Reset()
VideoEncoder::Reset() was accessing codec_context_ for FFmpeg flush operations before stopping the async worker thread. The worker could still be calling avcodec_send_frame() concurrently, causing SIGSEGV since AVCodecContext is not thread-safe. Fix: Stop async worker and release TSFNs first, then flush codec. This matches the safe pattern already used in VideoDecoder::Reset(). Also adds defensive null check for packet_ during flush.
1 parent 64b0daa commit f1b55c6

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

src/video_encoder.cc

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -887,16 +887,36 @@ Napi::Value VideoEncoder::Reset(const Napi::CallbackInfo& info) {
887887
return env.Undefined();
888888
}
889889

890-
// Flush any pending frames (don't emit - discard).
891-
if (codec_context_) {
890+
// CRITICAL: Stop async worker FIRST before accessing codec_context_.
891+
// The worker thread may be calling avcodec_send_frame() or avcodec_receive_packet()
892+
// concurrently. AVCodecContext is NOT thread-safe - concurrent access causes SIGSEGV.
893+
if (async_worker_) {
894+
async_worker_->Stop();
895+
async_worker_.reset();
896+
}
897+
898+
// Release ThreadSafeFunctions after worker is stopped.
899+
if (async_mode_) {
900+
output_tsfn_.Release();
901+
error_tsfn_.Release();
902+
async_mode_ = false;
903+
}
904+
905+
// Now safe to flush codec - worker is stopped.
906+
// Drain encoder's internal buffers, discard any remaining encoded packets.
907+
if (codec_context_ && packet_) {
892908
avcodec_send_frame(codec_context_.get(), nullptr);
893909
while (avcodec_receive_packet(codec_context_.get(), packet_.get()) == 0) {
894910
av_packet_unref(packet_.get());
895911
}
896912
}
897913

898914
// Clean up FFmpeg resources.
899-
Cleanup();
915+
frame_.reset();
916+
packet_.reset();
917+
sws_context_.reset();
918+
codec_context_.reset();
919+
codec_ = nullptr;
900920

901921
// Reset state.
902922
state_ = "unconfigured";

0 commit comments

Comments
 (0)