Skip to content

Commit

Permalink
fix: [windows] fix AgoraVideoView dispose crash due to multithreading
Browse files Browse the repository at this point in the history
  • Loading branch information
littleGnAl committed Mar 29, 2023
1 parent 930fbbe commit 216eb04
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 61 deletions.
32 changes: 18 additions & 14 deletions windows/include/agora_rtc_engine/texture_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,36 @@ class TextureRender : public agora::iris::IrisVideoFrameBufferDelegate

int64_t texture_id();

virtual void OnVideoFrameReceived(const IrisVideoFrame& video_frame,
const IrisVideoFrameBufferConfig* config,
bool resize) override;
virtual void OnVideoFrameReceived(const IrisVideoFrame &video_frame,
const IrisVideoFrameBufferConfig *config,
bool resize) override;

void UpdateData(unsigned int uid, const std::string &channelId, unsigned int videoSourceType);

void Dispose();
// Checks if texture registrar, texture id and texture are available.
bool TextureRegistered()
{
return registrar_ && texture_ && texture_id_ > -1;
}

private:
// void HandleMethodCall(
// const flutter::MethodCall<flutter::EncodableValue> &method_call,
// std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);

const FlutterDesktopPixelBuffer *CopyPixelBuffer(size_t width, size_t height);

public:
flutter::TextureRegistrar *registrar_;
agora::iris::IrisVideoFrameBufferManager *videoFrameBufferManager_;
flutter::TextureVariant texture_;
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> method_channel_;

int64_t texture_id_ = -1;
// std::unique_ptr<flutter::MethodCall<flutter::EncodableValue>> channel_;
// unsigned int uid_;
// std::string channel_id_;
std::mutex mutex_;
FlutterDesktopPixelBuffer *pixel_buffer_;

uint32_t frame_width_ = 0;
uint32_t frame_height_ = 0;

std::mutex buffer_mutex_;
std::vector<uint8_t> buffer_;
std::unique_ptr<flutter::TextureVariant> texture_;
std::unique_ptr<FlutterDesktopPixelBuffer> flutter_desktop_pixel_buffer_ =
nullptr;
};

#endif // TEXTURE_RENDER_H_
119 changes: 74 additions & 45 deletions windows/texture_render.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ TextureRender::TextureRender(flutter::BinaryMessenger *messenger,
flutter::TextureRegistrar *registrar,
agora::iris::IrisVideoFrameBufferManager *videoFrameBufferManager)
: registrar_(registrar),
videoFrameBufferManager_(videoFrameBufferManager),
texture_(PixelBufferTexture(std::bind(&TextureRender::CopyPixelBuffer,
this,
std::placeholders::_1,
std::placeholders::_2))),
pixel_buffer_(new FlutterDesktopPixelBuffer{nullptr, 0, 0})
videoFrameBufferManager_(videoFrameBufferManager)
{
texture_id_ = registrar_->RegisterTexture(&texture_);
// Create flutter desktop pixelbuffer texture;
texture_ =
std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture(
[this](size_t width,
size_t height) -> const FlutterDesktopPixelBuffer *
{
return this->CopyPixelBuffer(width, height);
}));

texture_id_ = registrar_->RegisterTexture(texture_.get());

method_channel_ = std::make_unique<MethodChannel<EncodableValue>>(
messenger,
Expand All @@ -30,6 +34,21 @@ TextureRender::TextureRender(flutter::BinaryMessenger *messenger,

TextureRender::~TextureRender()
{
if (videoFrameBufferManager_)
{
videoFrameBufferManager_->DisableVideoFrameBuffer(this);
videoFrameBufferManager_ = nullptr;
}

const std::lock_guard<std::mutex> lock(buffer_mutex_);

if (registrar_ && texture_id_ != -1)
{
registrar_->UnregisterTexture(texture_id_);

registrar_ = nullptr;
texture_id_ = -1;
}
}

int64_t TextureRender::texture_id() { return texture_id_; }
Expand All @@ -38,33 +57,64 @@ void TextureRender::OnVideoFrameReceived(const IrisVideoFrame &video_frame,
const IrisVideoFrameBufferConfig *config,
bool resize)
{
std::lock_guard<std::mutex> lock_guard(mutex_);
if (pixel_buffer_->width != video_frame.width ||
pixel_buffer_->height != video_frame.height)
std::lock_guard<std::mutex> lock_guard(buffer_mutex_);

const uint32_t bytes_per_pixel = 4;
const uint32_t pixels_total = video_frame.width * video_frame.height;
const uint32_t data_size = pixels_total * bytes_per_pixel;

if (buffer_.size() != data_size)
{
if (pixel_buffer_->buffer)
{
delete[] pixel_buffer_->buffer;
}
pixel_buffer_->buffer = new uint8_t[video_frame.y_buffer_length];
buffer_.resize(data_size);

flutter::EncodableMap args = {
{EncodableValue("width"), EncodableValue(video_frame.width)},
{EncodableValue("height"), EncodableValue(video_frame.height)}};
method_channel_->InvokeMethod("onSizeChanged", std::make_unique<EncodableValue>(EncodableValue(args)));
}
memcpy((void *)pixel_buffer_->buffer, video_frame.y_buffer,
video_frame.y_buffer_length);
pixel_buffer_->width = video_frame.width;
pixel_buffer_->height = video_frame.height;
registrar_->MarkTextureFrameAvailable(texture_id_);

std::copy(static_cast<uint8_t *>(video_frame.y_buffer), static_cast<uint8_t *>(video_frame.y_buffer) + data_size, buffer_.data());

frame_width_ = video_frame.width;
frame_height_ = video_frame.height;
if (TextureRegistered())
{
registrar_->MarkTextureFrameAvailable(texture_id_);
}
}

const FlutterDesktopPixelBuffer *
TextureRender::CopyPixelBuffer(size_t width, size_t height)
{
std::lock_guard<std::mutex> lock_guard(mutex_);
return pixel_buffer_;
std::unique_lock<std::mutex> buffer_lock(buffer_mutex_);

if (!TextureRegistered())
{
return nullptr;
}

if (!flutter_desktop_pixel_buffer_)
{
flutter_desktop_pixel_buffer_ =
std::make_unique<FlutterDesktopPixelBuffer>();

// Unlocks mutex after texture is processed.
flutter_desktop_pixel_buffer_->release_callback =
[](void *release_context)
{
auto mutex = reinterpret_cast<std::mutex *>(release_context);
mutex->unlock();
};
}

flutter_desktop_pixel_buffer_->buffer = buffer_.data();
flutter_desktop_pixel_buffer_->width = frame_width_;
flutter_desktop_pixel_buffer_->height = frame_height_;

// Releases unique_lock and set mutex pointer for release context.
flutter_desktop_pixel_buffer_->release_context = buffer_lock.release();

return flutter_desktop_pixel_buffer_.get();
}

void TextureRender::UpdateData(unsigned int uid, const std::string &channelId, unsigned int videoSourceType)
Expand All @@ -73,7 +123,7 @@ void TextureRender::UpdateData(unsigned int uid, const std::string &channelId, u
IrisVideoFrameBufferConfig config;

config.id = uid;
config.type = (IrisVideoSourceType)videoSourceType; //::kVideoSourceTypeCameraPrimary;
config.type = (IrisVideoSourceType)videoSourceType;

if (!channelId.empty())
{
Expand All @@ -83,29 +133,8 @@ void TextureRender::UpdateData(unsigned int uid, const std::string &channelId, u
{
strcpy_s(config.key, "");
}
videoFrameBufferManager_->EnableVideoFrameBuffer(buffer, &config);
}

void TextureRender::Dispose()
{
if (videoFrameBufferManager_)
{
videoFrameBufferManager_->DisableVideoFrameBuffer(this);
}

if (texture_id_ != -1)
{
registrar_->UnregisterTexture(texture_id_);
texture_id_ = -1;
}

if (pixel_buffer_)
{
if (pixel_buffer_->buffer)
{
delete[] pixel_buffer_->buffer;
}
delete pixel_buffer_;
pixel_buffer_ = nullptr;
videoFrameBufferManager_->EnableVideoFrameBuffer(buffer, &config);
}
}
2 changes: 0 additions & 2 deletions windows/video_view_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ bool VideoViewController::DestroyTextureRender(int64_t textureId)
auto it = renderers_.find(textureId);
if (it != renderers_.end())
{
it->second.get()->Dispose();

renderers_.erase(it);
return true;
}
Expand Down

0 comments on commit 216eb04

Please sign in to comment.