Copy the decoded frame instead of aliasing the decoder's buffer

wxImage with static_data set stores the pointer and never copies it, so the
frame handed to wxMediaCtrl3 aliased AVVideoDecoder::bits_. That buffer is
rewritten by the next sws_scale with the mutex released, reallocated by
bits_.resize() when the window grows, and freed outright when the decoder
leaves PlayThread's loop body at end of stream, all while the GUI thread may
be painting from it.

Windows is unaffected either way, since toWxBitmap already copies the bits
into GDI.
This commit is contained in:
SoftFever
2026-08-30 11:19:06 +08:00
parent dfb102f68d
commit 600f0f20bd

View File

@@ -115,7 +115,10 @@ bool AVVideoDecoder::toWxImage(wxImage &image, wxSize const &size2)
if (result_h != size.GetHeight()) {
return false;
}
image = wxImage(size.GetWidth(), size.GetHeight(), bits_.data(), true);
// Copy: the frame outlives this decoder and is painted by the GUI thread while the
// next sws_scale is already overwriting bits_, so it must own its pixels. The Windows
// path below needs no equivalent, wxBitmap copies the bits into GDI.
image = wxImage(size.GetWidth(), size.GetHeight(), bits_.data(), true).Copy();
if (!image.IsOk()) {
fprintf(stderr, "AVVideoDecoder: image not ok %dx%d\n", size.GetWidth(), size.GetHeight());
return false;