Skip to content

Commit 70df13e

Browse files
authored
0034 BaseRenderer の描画バッファ境界超過を修正する (#357)
* 0034 BaseRenderer の描画バッファ境界超過を修正する * 0034 解決方法を追記する * 0034 closed BaseRenderer の描画バッファがウィンドウリサイズ時に境界を超過する
1 parent c136f87 commit 70df13e

3 files changed

Lines changed: 38 additions & 62 deletions

File tree

CHANGES.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,16 @@
138138
- 参考: Boost.Asio 1.91 で BOOST_ASIO_ENABLE_VERSION_NAMESPACE による
139139
inline namespace のバイナリバージョニングが
140140
追加されたが、前方宣言を壊す可能性があるためデフォルト無効とされている
141-
該当記載のある boost のドキュメント :
141+
該当記載のある boost のドキュメント :
142142
```
143143
Added optional binary versioning using an inline namespace. ... The inline
144144
namespace is disabled by default to avoid breaking existing code that forward
145145
declares Asio names
146146
```
147147
- リンク : https://www.boost.org/doc/libs/1_91_0/doc/html/boost_asio/history.html
148148
- @torikizi
149+
- [FIX] BaseRenderer の描画バッファがウィンドウリサイズ時に境界を超過する問題を修正する
150+
- @voluntas
149151
- [FIX] sumomo と sdl_sample で AddTrack の戻り値チェックを追加する
150152
- @melpon
151153
- [FIX] VPL デコーダ `InitVpl` で `CreateDecoder` の nullptr 戻り値未チェックを修正する
@@ -562,9 +564,9 @@
562564
- [UPDATE] Android SDK Command-line tools のバージョンを 13114758 にあげる
563565
- @melpon
564566
- [UPDATE] `NVIDIA Video Codec SDK` を [13.0](https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/index.html) にアップデートする
565-
- NVIDIA Video Codec SDK で新たに追加された `NvEncOutputFrame` 構造体に対応する
566-
- `v_packet_` を `std::vector<std::vector<uint8_t>>` から `std::vector<NvEncOutputFrame>` に変更する
567-
- `for (std::vector<uint8_t>& packet : v_packet_)` を `for (NvEncOutputFrame& output : v_packet_)` に変更する
567+
- NVIDIA Video Codec SDK で新たに追加された `NvEncOutputFrame` 構造体に対応する
568+
- `v_packet_` を `std::vector<std::vector<uint8_t>>` から `std::vector<NvEncOutputFrame>` に変更する
569+
- `for (std::vector<uint8_t>& packet : v_packet_)` を `for (NvEncOutputFrame& output : v_packet_)` に変更する
568570
- ループ内に `std::vector<uint8_t>& packet = output.frame;` を追加し、既存処理との互換性を維持する
569571
- コーデックごとに実行していたキーフレーム判定を NvEncOutputFrame のフレーム情報を利用して行うように変更する
570572
- @torikizi
@@ -697,7 +699,7 @@
697699
- @melpon
698700
- [CHANGE] `SoraVideoEncoderFactoryConfig` の `force_i420_conversion_for_simulcast_adapter` を `force_i420_conversion` に変更
699701
- @melpon
700-
- [CHANGE] GitHub Actions で macOS 向けビルドで Xcode のバージョンを指定したのを削除する
702+
- [CHANGE] GitHub Actions で macOS 向けビルドで Xcode のバージョンを指定したのを削除する
701703
- libwebrtc の制約で Xcode のバージョンを指定していたが、 m132.6834.5.5 の時点では制約がなくなり、指定しなくてもビルドできるようになったため
702704
- @torikizi
703705
- [CHANGE] Ubuntu 20.04 x86_64 の対応を削除
@@ -718,7 +720,7 @@
718720
- [ADD] OpenH264 デコーダに対応する
719721
- @melpon
720722
- [ADD] タグが打たれた場合に sumomo バイナリを Release に追加する
721-
- Release 用の sumomo は C++ SDK のリリースバイナリを使用してビルドする
723+
- Release 用の sumomo は C++ SDK のリリースバイナリを使用してビルドする
722724
- リアルタイムメッセージング以外の機能がほぼ全て含まれている sumomo をリリース時に含めるようにする
723725
- @torikizi
724726
- [ADD] NVIDIA Video Codec SDK を AV1 エンコーダー/デコーダーに対応する

issues/0034-bug-fix-base-renderer-buffer-overflow-on-resize.md renamed to issues/closed/0034-bug-fix-base-renderer-buffer-overflow-on-resize.md

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
- Priority: High
44
- Created: 2026-07-14
5-
- Completed: {YYYY-MM-DD}
5+
- Completed: 2026-07-27
66
- Model: DeepSeek V4 Pro
77
- Branch: feature/fix-base-renderer-buffer-overflow-on-resize
88
- Polished: 2026-07-27
@@ -136,54 +136,19 @@ sumomo をローカルの SDK 実装と紐付けてデスクトップ向けに
136136

137137
## 解決方法
138138

139-
`BaseRenderer::RenderThread()` を次の順序へ変更する。
140-
`<vector>``<cstring>` は既に利用可能なため、追加の依存は不要である。
141-
以下は描画用バッファに関係する変更箇所だけを示し、フレームレート制御は省略する。
139+
`BaseRenderer::RenderThread()` の描画用バッファを `std::vector<uint8_t>` に変更し、各描画イテレーションで現在のキャンバス寸法に合わせて `resize()` するようにした。
142140

143-
```cpp
144-
std::vector<uint8_t> image;
141+
キャンバス寸法のスナップショット、描画用バッファのサイズ変更とクリア、各 Sink の合成を同じ `sinks_lock_` の保持中に実行する。
142+
これにより、`SetSize()` と描画処理が並行しても、バッファサイズ、Y offset、stride、Sink の outline が同じキャンバス寸法に基づくようにした。
143+
`Render()` は従来どおりロック外で呼び出し、スナップショットした寸法と `resize()` 後のバッファを渡す。
145144

146-
while (running_) {
147-
std::vector<SinkInfo> sink_infos;
148-
int canvas_width = 0;
149-
int canvas_height = 0;
150-
151-
{
152-
webrtc::MutexLock lock(&sinks_lock_);
153-
canvas_width = width_;
154-
canvas_height = height_;
155-
image.resize(static_cast<size_t>(canvas_width) *
156-
static_cast<size_t>(canvas_height) * 4);
157-
memset(image.data(), 0, image.size());
158-
159-
for (const VideoTrackSinkVector::value_type& sinks : sinks_) {
160-
Sink* sink = sinks.second.get();
161-
webrtc::MutexLock frame_lock(sink->GetMutex());
162-
if (sink->GetOutlineChanged()) {
163-
continue;
164-
}
165-
166-
int width = sink->GetFrameWidth();
167-
int height = sink->GetFrameHeight();
168-
if (width == 0 || height == 0) {
169-
continue;
170-
}
171-
172-
libyuv::ARGBCopy(sink->GetImage(), width * 4,
173-
image.data() + sink->GetOffsetX() * 4 +
174-
sink->GetOffsetY() * canvas_width * 4,
175-
canvas_width * 4, width, height);
176-
177-
// SinkInfo の構築は現行どおり
178-
}
179-
}
180-
181-
Render(image.data(), canvas_width, canvas_height, sink_infos);
182-
}
183-
```
145+
SDL、ANSI、Sixel の各レンダラーが `Render()` の呼び出し中に画像を同期的に消費し、返却後にポインタを保持しないことも確認した。
184146

185-
### 注意点
147+
次の検証を実施した。
186148

187-
- `resize()` より前に取得した `data()` は再確保によって無効になりうるため、必ず `resize()` の後で `image.data()` を使う
188-
- Sink ごとの `image_``Sink::OnFrame()` 内で outline または入力解像度が変わったときに再確保されるため、本修正の対象外とする
189-
- ロック順序は現行どおり `sinks_lock_` から Sink の mutex の順とし、逆順の取得を追加しない
149+
- SDK のテストを含む macOS ARM64 ビルド
150+
- ローカル SDK を使用した sumomo の macOS ARM64 ビルド
151+
- `test_sumomo_sendonly_recvonly[VP8]` の E2E
152+
- AddressSanitizer を有効にした SDK と sumomo のクリーンビルド
153+
- F キー処理と同じ SDL フルスクリーン切替を 3 往復、ウィンドウ拡大、`--fullscreen` 起動
154+
- 各リサイズ後にクラッシュと `heap-buffer-overflow` が発生せず、fake 映像の描画が継続すること

src/renderer/base_renderer.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,24 @@ void BaseRenderer::SetSize(int width, int height) {
7171
void BaseRenderer::RenderThread() {
7272
RenderThreadStarted();
7373

74-
std::unique_ptr<uint8_t[]> image(new uint8_t[width_ * height_ * 4]);
74+
std::vector<uint8_t> image;
7575

7676
while (running_) {
77-
memset(image.get(), 0, width_ * height_ * 4);
78-
79-
auto frame_start = std::chrono::steady_clock::now();
77+
std::chrono::steady_clock::time_point frame_start;
8078
std::vector<SinkInfo> sink_infos;
79+
int canvas_width = 0;
80+
int canvas_height = 0;
8181
{
8282
webrtc::MutexLock lock(&sinks_lock_);
83+
// SetSize() と競合してもキャンバス寸法と描画バッファのサイズが
84+
// 食い違わないよう、Sink の合成まで同じロック下で処理する。
85+
canvas_width = width_;
86+
canvas_height = height_;
87+
image.resize(static_cast<size_t>(canvas_width) *
88+
static_cast<size_t>(canvas_height) * 4);
89+
memset(image.data(), 0, image.size());
90+
frame_start = std::chrono::steady_clock::now();
91+
8392
for (const VideoTrackSinkVector::value_type& sinks : sinks_) {
8493
Sink* sink = sinks.second.get();
8594

@@ -97,9 +106,9 @@ void BaseRenderer::RenderThread() {
97106
}
98107

99108
libyuv::ARGBCopy(sink->GetImage(), width * 4,
100-
image.get() + sink->GetOffsetX() * 4 +
101-
sink->GetOffsetY() * width_ * 4,
102-
width_ * 4, width, height);
109+
image.data() + sink->GetOffsetX() * 4 +
110+
sink->GetOffsetY() * canvas_width * 4,
111+
canvas_width * 4, width, height);
103112

104113
SinkInfo info;
105114
info.offset_x = sink->GetOffsetX();
@@ -114,7 +123,7 @@ void BaseRenderer::RenderThread() {
114123
}
115124
}
116125

117-
Render(image.get(), width_, height_, sink_infos);
126+
Render(image.data(), canvas_width, canvas_height, sink_infos);
118127

119128
// フレームレート制御
120129
auto frame_end = std::chrono::steady_clock::now();

0 commit comments

Comments
 (0)