NEW: reimpl wxMediaCtrl from ffmpeg

Jira: none
Change-Id: I46a47118a7649b2a50fcce8911e2888342ef25de
(cherry picked from commit d6c7f08769c8cfdbbf0e80ad280c9b3408a3c27d)
This commit is contained in:
chunmao.guo 2024-06-26 19:51:59 +08:00 committed by Lane.Wei
parent 76ef39c588
commit 94d91be60b
15 changed files with 710 additions and 112 deletions

View File

@ -167,6 +167,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
# We pick it from environment if it is not defined in another way
if(WIN32)
find_package(PkgConfig REQUIRED)
if(NOT DEFINED WIN10SDK_PATH)
if(DEFINED ENV{WIN10SDK_PATH})
set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
@ -619,6 +620,10 @@ function(bambustudio_copy_dlls target config postfix output_dlls)
${CMAKE_PREFIX_PATH}/bin/occt/TKXDESTEP.dll
${CMAKE_PREFIX_PATH}/bin/occt/TKXSBase.dll
${CMAKE_PREFIX_PATH}/bin/freetype.dll
${CMAKE_PREFIX_PATH}/bin/avcodec-59.dll
${CMAKE_PREFIX_PATH}/bin/swresample-4.dll
${CMAKE_PREFIX_PATH}/bin/swscale-6.dll
${CMAKE_PREFIX_PATH}/bin/avutil-57.dll
DESTINATION ${_out_dir})
set(${output_dlls}
@ -654,11 +659,34 @@ function(bambustudio_copy_dlls target config postfix output_dlls)
${_out_dir}/TKXSBase.dll
${_out_dir}/freetype.dll
${_out_dir}/avcodec-59.dll
${_out_dir}/swresample-4.dll
${_out_dir}/swscale-6.dll
${_out_dir}/avutil-57.dll
PARENT_SCOPE
)
endfunction()
function(bambustudio_copy_sos target config postfix output_sos)
set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
message ("set out_dir to CMAKE_CURRENT_BINARY_DIR: ${_out_dir}")
file(COPY ${CMAKE_PREFIX_PATH}/lib/libavcodec.so
${CMAKE_PREFIX_PATH}/lib/libavutil.so
${CMAKE_PREFIX_PATH}/lib/libswscale.so
${CMAKE_PREFIX_PATH}/lib/libswresample.so
DESTINATION ${_out_dir})
set(${output_dlls}
${_out_dir}/libavcodec.so
${_out_dir}/libavutil.so
${_out_dir}/libswscale.so
${_out_dir}/libswresample.so
PARENT_SCOPE
)
endfunction()
# libslic3r, BambuStudio GUI and the BambuStudio executable.
add_subdirectory(src)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 579 KiB

View File

@ -218,6 +218,16 @@ if (WIN32)
else ()
if (NOT APPLE)
set(output_sos_Release "")
set(output_sos_Debug "")
add_custom_target(BambuStudioSosCopy ALL DEPENDS BambuStudio)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
bambustudio_copy_sos(BambuStudioSosCopy "Debug" "d" output_sos_Debug)
else()
bambustudio_copy_sos(BambuStudioSosCopy "Release" "" output_sos_Release)
endif()
endif()
if (APPLE AND NOT CMAKE_MACOSX_BUNDLE)
# On OSX, the name of the binary matches the name of the Application.
add_custom_command(TARGET BambuStudio POST_BUILD
@ -275,5 +285,9 @@ if (WIN32)
endif ()
install(FILES ${output_dlls_${build_type}} DESTINATION "${CMAKE_INSTALL_PREFIX}")
else ()
if (APPLE)
else()
install(FILES ${output_sos_${build_type}} DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()
install(TARGETS BambuStudio RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
endif ()

View File

@ -546,12 +546,17 @@ if (APPLE)
GUI/InstanceCheckMac.h
GUI/wxMediaCtrl2.mm
GUI/wxMediaCtrl2.h
GUI/wxMediaCtrl3.h
)
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
else ()
list(APPEND SLIC3R_GUI_SOURCES
GUI/AVVideoDecoder.cpp
GUI/AVVideoDecoder.hpp
GUI/wxMediaCtrl2.cpp
GUI/wxMediaCtrl2.h
GUI/wxMediaCtrl3.cpp
GUI/wxMediaCtrl3.h
)
endif ()
@ -608,6 +613,15 @@ if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
endif ()
if (NOT APPLE)
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
libavcodec
libswscale
libavutil
)
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
endif()
# We need to implement some hacks for wxWidgets and touch the underlying GTK
# layer and sub-libraries. This forces us to use the include locations and
# link these libraries.

View File

@ -0,0 +1,126 @@
#include "AVVideoDecoder.hpp"
extern "C"
{
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}
AVVideoDecoder::AVVideoDecoder()
{
codec_ctx_ = avcodec_alloc_context3(nullptr);
}
AVVideoDecoder::~AVVideoDecoder()
{
if (sws_ctx_)
sws_freeContext(sws_ctx_);
if (frame_)
av_frame_free(&frame_);
if (codec_ctx_)
avcodec_free_context(&codec_ctx_);
}
int AVVideoDecoder::open(Bambu_StreamInfo const &info)
{
auto codec_id = info.sub_type == AVC1 ? AV_CODEC_ID_H264 : AV_CODEC_ID_MJPEG;
auto codec = avcodec_find_decoder(codec_id);
if (codec == nullptr) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
/* open the coderc */
if (avcodec_open2(codec_ctx_, codec, nullptr) < 0) {
fprintf(stderr, "could not open codec\n");
return -1;
}
// Allocate an AVFrame structure
frame_ = av_frame_alloc();
if (frame_ == nullptr)
return -1;
return 0;
}
int AVVideoDecoder::decode(const Bambu_Sample &sample)
{
auto pkt = av_packet_alloc();
int ret = av_new_packet(pkt, sample.size);
if (ret == 0)
memcpy(pkt->data, sample.buffer, size_t(sample.size));
got_frame_ = avcodec_receive_frame(codec_ctx_, frame_) == 0;
ret = avcodec_send_packet(codec_ctx_, pkt);
return ret;
}
int AVVideoDecoder::flush()
{
int ret = avcodec_send_packet(codec_ctx_, nullptr);
got_frame_ = avcodec_receive_frame(codec_ctx_, frame_) == 0;
return ret;
}
void AVVideoDecoder::close()
{
}
bool AVVideoDecoder::toWxImage(wxImage &image, wxSize const &size2)
{
if (!got_frame_)
return false;
auto size = size2;
if (!size.IsFullySpecified())
size = {frame_->width, frame_->height };
if (size.GetWidth() & 0x0f)
size.SetWidth((size.GetWidth() & ~0x0f) + 0x10);
AVPixelFormat wxFmt = AV_PIX_FMT_RGB24;
sws_ctx_ = sws_getCachedContext(sws_ctx_,
frame_->width, frame_->height, AVPixelFormat(frame_->format),
size.GetWidth(), size.GetHeight(), wxFmt,
SWS_POINT, // SWS_FAST_BILINEAR //SWS_BICUBIC
nullptr, nullptr, nullptr);
uint8_t *data = (uint8_t*)malloc(size.GetWidth() * size.GetHeight() * 3);
if (data == nullptr)
return false;
uint8_t * datas[] = {data };
int strides[] = {size.GetWidth() * 3};
int result_h = sws_scale(sws_ctx_, frame_->data, frame_->linesize, 0, frame_->height, datas, strides);
if (result_h != size.GetHeight()) {
delete[] data;
return false;
}
image = wxImage(size.GetWidth(), size.GetHeight(), data);
return true;
}
bool AVVideoDecoder::toWxBitmap(wxBitmap &bitmap, wxSize const &size2)
{
if (!got_frame_)
return false;
auto size = size2;
if (!size.IsFullySpecified())
size = {frame_->width, frame_->height };
if (size.GetWidth() & 0x0f)
size.SetWidth((size.GetWidth() & ~0x0f) + 0x10);
AVPixelFormat wxFmt = AV_PIX_FMT_RGB32;
sws_ctx_ = sws_getCachedContext(sws_ctx_,
frame_->width, frame_->height, AVPixelFormat(frame_->format),
size.GetWidth(), size.GetHeight(), wxFmt,
SWS_POINT, // SWS_FAST_BILINEAR //SWS_BICUBIC
nullptr, nullptr, nullptr);
uint8_t *data = (uint8_t*)malloc(size.GetWidth() * size.GetHeight() * 4);
if (data == nullptr)
return false;
uint8_t *datas[] = {data};
int strides[] = {size.GetWidth() * 4};
int result_h = sws_scale(sws_ctx_, frame_->data, frame_->linesize, 0, frame_->height, datas, strides);
if (result_h != size.GetHeight()) {
delete[] data;
return false;
}
bitmap = wxBitmap((char *) data, size.GetWidth(), size.GetHeight(), 32);
return true;
}

View File

@ -0,0 +1,39 @@
#ifndef AVVIDEODECODER_HPP
#define AVVIDEODECODER_HPP
#include "BambuTunnel.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
class wxBitmap;
class AVVideoDecoder
{
public:
AVVideoDecoder();
~AVVideoDecoder();
public:
int open(Bambu_StreamInfo const &info);
int decode(Bambu_Sample const &sample);
int flush();
void close();
bool toWxImage(wxImage &image, wxSize const &size);
bool toWxBitmap(wxBitmap &bitmap, wxSize const & size);
private:
AVCodecContext *codec_ctx_ = nullptr;
AVFrame * frame_ = nullptr;
SwsContext * sws_ctx_ = nullptr;
bool got_frame_ = false;
};
#endif // AVVIDEODECODER_HPP

View File

@ -49,6 +49,7 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w
SetLabel("MediaPlayCtrl");
SetBackgroundColour(*wxWHITE);
m_media_ctrl->Bind(wxEVT_MEDIA_STATECHANGED, &MediaPlayCtrl::onStateChanged, this);
m_media_ctrl->SetIdleImage(from_u8(resources_dir() + "/images/live_stream_default.png"));
m_button_play = new Button(this, "", "media_play", wxBORDER_NONE);
m_button_play->SetCanFocus(false);
@ -914,25 +915,19 @@ static int SecondsSinceLastInput()
}}
void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height)
{
#ifdef __WXMAC__
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
#else
wxMediaCtrl::DoSetSize(x, y, width, height, sizeFlags);
#endif
if (sizeFlags & wxSIZE_USE_EXISTING) return;
wxSize size = m_video_size;
wxSize size = videoSize;
if (!size.IsFullySpecified()) size = {16, 9};
int maxHeight = (width * size.GetHeight() + size.GetHeight() - 1) / size.GetWidth();
if (maxHeight != GetMaxHeight()) {
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2::DoSetSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight;
SetMaxSize({-1, maxHeight});
CallAfter([this] {
if (auto p = GetParent()) {
if (maxHeight != ctrl->GetMaxHeight()) {
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl_OnSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight;
ctrl->SetMaxSize({-1, maxHeight});
ctrl->CallAfter([ctrl] {
if (auto p = ctrl->GetParent()) {
p->Layout();
p->Refresh();
}
});
}
}

View File

@ -8,7 +8,14 @@
#ifndef MediaPlayCtrl_h
#define MediaPlayCtrl_h
#define USE_WX_MEDIA_CTRL_2 0
#if USE_WX_MEDIA_CTRL_2
#include "wxMediaCtrl2.h"
#define wxMediaCtrl3 wxMediaCtrl2
#else
#include "wxMediaCtrl3.h"
#endif
#include <wx/panel.h>
@ -31,7 +38,7 @@ namespace GUI {
class MediaPlayCtrl : public wxPanel
{
public:
MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
MediaPlayCtrl(wxWindow *parent, wxMediaCtrl3 *media_ctrl, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
~MediaPlayCtrl();
@ -73,7 +80,7 @@ private:
static constexpr wxMediaState MEDIASTATE_LOADING = (wxMediaState) 5;
static constexpr wxMediaState MEDIASTATE_BUFFERING = (wxMediaState) 6;
wxMediaCtrl2 * m_media_ctrl;
wxMediaCtrl3 * m_media_ctrl;
wxMediaState m_last_state = MEDIASTATE_IDLE;
std::string m_machine;
int m_lan_proto = 0;

View File

@ -1012,7 +1012,7 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page()
// media_ctrl_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
// media_ctrl_panel->SetBackgroundColour(*wxBLACK);
// wxBoxSizer *bSizer_monitoring = new wxBoxSizer(wxVERTICAL);
m_media_ctrl = new wxMediaCtrl2(this);
m_media_ctrl = new wxMediaCtrl3(this);
m_media_ctrl->SetMinSize(wxSize(PAGE_MIN_WIDTH, FromDIP(288)));
m_media_play_ctrl = new MediaPlayCtrl(this, m_media_ctrl, wxDefaultPosition, wxSize(-1, FromDIP(40)));
@ -2576,6 +2576,11 @@ void StatusPanel::update_ams(MachineObject *obj)
m_ams_control->show_auto_refill(false);
}
else {
<<<<<<< HEAD (26a4fc ENH: refresh_agora_url callback)
=======
m_ams_control->SetAmsModel(ams_mode, ams_mode);
>>>>>>> CHANGE (d6c7f0 NEW: reimpl wxMediaCtrl from ffmpeg)
m_ams_control->SetAmsModel(ams_mode, ams_mode);
show_ams_group(true);

View File

@ -13,7 +13,6 @@
#include <wx/sizer.h>
#include <wx/gbsizer.h>
#include <wx/webrequest.h>
#include "wxMediaCtrl2.h"
#include "MediaPlayCtrl.h"
#include "AMSSetting.hpp"
#include "Calibration.hpp"
@ -313,7 +312,7 @@ protected:
wxStaticBitmap *m_bitmap_static_use_weight;
wxMediaCtrl2 * m_media_ctrl;
wxMediaCtrl3 * m_media_ctrl;
MediaPlayCtrl * m_media_play_ctrl;
Label * m_staticText_printing;

View File

@ -1,6 +1,6 @@
#include "wxMediaCtrl2.h"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "libslic3r/Utils.hpp"
#ifdef __WIN32__
#include <versionhelpers.h>
#include <wx/msw/registry.h>
@ -194,8 +194,9 @@ void wxMediaCtrl2::Play() { wxMediaCtrl::Play(); }
void wxMediaCtrl2::Stop()
{
wxMediaCtrl::Stop();
}
wxMediaCtrl::Stop(); }
void wxMediaCtrl2::SetIdleImage(wxString const &image) {}
#ifdef __LINUX__
extern "C" int gst_bambu_last_error;
@ -230,6 +231,13 @@ wxSize wxMediaCtrl2::DoGetBestSize() const
return {-1, -1};
}
void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
if (sizeFlags & wxSIZE_USE_EXISTING) return;
wxMediaCtrl_OnSize(this, m_video_size, width, height);
}
#ifdef __WIN32__
WXLRESULT wxMediaCtrl2::MSWWindowProc(WXUINT nMsg,

View File

@ -13,6 +13,8 @@
wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
#ifdef __WXMAC__
class wxMediaCtrl2 : public wxWindow
@ -41,7 +43,7 @@ public:
protected:
void DoSetSize(int x, int y, int width, int height, int sizeFlags) override;
static void bambu_log(void const * ctx, int level, char const * msg);
static void bambu_log(void const *ctx, int level, char const *msg);
void NotifyStopped();

View File

@ -140,6 +140,10 @@ void wxMediaCtrl2::Stop()
NotifyStopped();
}
void wxMediaCtrl2::SetIdleImage(wxString const &image)
{
}
void wxMediaCtrl2::NotifyStopped()
{
if (m_state != wxMEDIASTATE_STOPPED) {
@ -168,3 +172,10 @@ wxSize wxMediaCtrl2::GetVideoSize() const
return {0, 0};
}
}
void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
if (sizeFlags & wxSIZE_USE_EXISTING) return;
wxMediaCtrl_OnSize(this, m_video_size, width, height);
}

View File

@ -0,0 +1,267 @@
#include "wxMediaCtrl3.h"
#include "AVVideoDecoder.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#ifdef __WIN32__
#include <versionhelpers.h>
#include <wx/msw/registry.h>
#include <shellapi.h>
#endif
//wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
BEGIN_EVENT_TABLE(wxMediaCtrl3, wxWindow)
// catch paint events
EVT_PAINT(wxMediaCtrl3::paintEvent)
END_EVENT_TABLE()
struct StaticBambuLib : BambuLib
{
static StaticBambuLib &get();
};
wxMediaCtrl3::wxMediaCtrl3(wxWindow *parent)
: wxWindow(parent, wxID_ANY)
, BambuLib(StaticBambuLib::get())
, m_thread([this] { PlayThread(); })
{
SetBackgroundColour(*wxBLACK);
}
wxMediaCtrl3::~wxMediaCtrl3()
{
{
std::unique_lock<std::mutex> lk(m_mutex);
m_url.reset(new wxURI);
m_frame = wxImage(m_idle_image);
m_cond.notify_all();
}
m_thread.join();
}
void wxMediaCtrl3::Load(wxURI url)
{
std::unique_lock<std::mutex> lk(m_mutex);
m_video_size = wxDefaultSize;
m_error = 0;
m_url.reset(new wxURI(url));
m_cond.notify_all();
}
void wxMediaCtrl3::Play()
{
std::unique_lock<std::mutex> lk(m_mutex);
if (m_state != wxMEDIASTATE_PLAYING) {
m_state = wxMEDIASTATE_PLAYING;
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
event.SetId(GetId());
event.SetEventObject(this);
wxPostEvent(this, event);
}
}
void wxMediaCtrl3::Stop()
{
std::unique_lock<std::mutex> lk(m_mutex);
m_url.reset();
m_frame = wxImage(m_idle_image);
m_cond.notify_all();
Refresh();
}
void wxMediaCtrl3::SetIdleImage(wxString const &image)
{
if (m_idle_image == image)
return;
m_idle_image = image;
if (m_url == nullptr) {
std::unique_lock<std::mutex> lk(m_mutex);
m_frame = wxImage(m_idle_image);
assert(m_frame.IsOk());
Refresh();
}
}
wxMediaState wxMediaCtrl3::GetState()
{
std::unique_lock<std::mutex> lk(m_mutex);
return m_state;
}
int wxMediaCtrl3::GetLastError()
{
std::unique_lock<std::mutex> lk(m_mutex);
return m_error;
}
wxSize wxMediaCtrl3::GetVideoSize()
{
std::unique_lock<std::mutex> lk(m_mutex);
return m_video_size;
}
wxSize wxMediaCtrl3::DoGetBestSize() const
{
return {-1, -1};
}
static void adjust_frame_size(wxSize & frame, wxSize const & video, wxSize const & window)
{
if (video.x * window.y < video.y * window.x)
frame = { video.x * window.y / video.y, window.y };
else
frame = { window.x, video.y * window.x / video.x };
}
void wxMediaCtrl3::paintEvent(wxPaintEvent &evt)
{
wxPaintDC dc(this);
auto size = GetSize();
std::unique_lock<std::mutex> lk(m_mutex);
if (!m_frame.IsOk())
return;
auto size2 = m_frame.GetSize();
if (size2.x != m_frame_size.x && size2.y == m_frame_size.y)
size2.x = m_frame_size.x;
if (size2.x != size.x && size2.y != size.y) {
auto scale = std::min(double(size.x) / size2.x, double(size.y) / size2.y);
dc.SetUserScale(scale, scale);
adjust_frame_size(size2, size2, size);
}
size2 = (size - size2) / 2;
dc.DrawBitmap(m_frame, size2.x, size2.y);
}
void wxMediaCtrl3::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
if (sizeFlags & wxSIZE_USE_EXISTING) return;
wxMediaCtrl_OnSize(this, m_video_size, width, height);
}
void wxMediaCtrl3::bambu_log(void *ctx, int level, tchar const *msg2)
{
#ifdef _WIN32
wxString msg(msg2);
#else
wxString msg = wxString::FromUTF8(msg2);
#endif
if (level == 1) {
if (msg.EndsWith("]")) {
int n = msg.find_last_of('[');
if (n != wxString::npos) {
long val = 0;
wxMediaCtrl3 *ctrl = (wxMediaCtrl3 *) ctx;
if (msg.SubString(n + 1, msg.Length() - 2).ToLong(&val)) {
std::unique_lock<std::mutex> lk(ctrl->m_mutex);
ctrl->m_error = (int) val;
}
}
} else if (msg.Contains("stat_log")) {
wxCommandEvent evt(EVT_MEDIA_CTRL_STAT);
wxMediaCtrl3 *ctrl = (wxMediaCtrl3 *) ctx;
evt.SetEventObject(ctrl);
evt.SetString(msg.Mid(msg.Find(' ') + 1));
wxPostEvent(ctrl, evt);
}
}
BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
}
void wxMediaCtrl3::PlayThread()
{
using namespace std::chrono_literals;
std::shared_ptr<wxURI> url;
std::unique_lock<std::mutex> lk(m_mutex);
while (true) {
m_cond.wait(lk, [this, &url] { return m_url != url; });
url = m_url;
if (url == nullptr)
continue;
if (!url->HasScheme())
break;
lk.unlock();
Bambu_Tunnel tunnel = nullptr;
int error = Bambu_Create(&tunnel, m_url->BuildURI().ToUTF8());
if (error == 0) {
Bambu_SetLogger(tunnel, &wxMediaCtrl3::bambu_log, this);
error = Bambu_Open(tunnel);
if (error == 0)
error = Bambu_would_block;
}
lk.lock();
while (error == int(Bambu_would_block)) {
m_cond.wait_for(lk, 100ms);
if (m_url != url) {
error = 1;
break;
}
lk.unlock();
error = Bambu_StartStream(tunnel, true);
lk.lock();
}
Bambu_StreamInfo info;
if (error == 0)
error = Bambu_GetStreamInfo(tunnel, 0, &info);
AVVideoDecoder decoder;
if (error == 0) {
decoder.open(info);
m_video_size = { info.format.video.width, info.format.video.height };
adjust_frame_size(m_frame_size, m_video_size, GetSize());
NotifyStopped();
}
Bambu_Sample sample;
while (error == 0) {
lk.unlock();
error = Bambu_ReadSample(tunnel, &sample);
lk.lock();
while (error == int(Bambu_would_block)) {
m_cond.wait_for(lk, 100ms);
if (m_url != url) {
error = 1;
break;
}
lk.unlock();
error = Bambu_ReadSample(tunnel, &sample);
lk.lock();
}
if (error == 0) {
if (m_url != url) {
error = 1;
break;
}
lk.unlock();
wxBitmap bm;
decoder.decode(sample);
decoder.toWxBitmap(bm, m_frame_size);
lk.lock();
if (bm.IsOk())
m_frame = bm;
CallAfter([this] { Refresh(); });
}
}
if (tunnel) {
lk.unlock();
Bambu_Close(tunnel);
Bambu_Destroy(tunnel);
tunnel = nullptr;
lk.lock();
}
if (m_url == url)
m_error = error;
m_video_size = wxDefaultSize;
NotifyStopped();
}
}
void wxMediaCtrl3::NotifyStopped()
{
m_state = wxMEDIASTATE_STOPPED;
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
event.SetId(GetId());
event.SetEventObject(this);
wxPostEvent(this, event);
}

View File

@ -0,0 +1,83 @@
//
// wxMediaCtrl3.h
// libslic3r_gui
//
// Created by cmguo on 2024/6/22.
//
#ifndef wxMediaCtrl3_h
#define wxMediaCtrl3_h
#include "wx/uri.h"
#include "wx/mediactrl.h"
wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
#ifdef __WXMAC__
#include "wxMediaCtrl2.h"
#define wxMediaCtrl3 wxMediaCtrl2
#else
#define BAMBU_DYNAMIC
#include <BambuTunnel.h>
class AVVideoDecoder;
class wxMediaCtrl3 : public wxWindow, BambuLib
{
public:
wxMediaCtrl3(wxWindow *parent);
~wxMediaCtrl3();
void Load(wxURI url);
void Play();
void Stop();
void SetIdleImage(wxString const & image);
wxMediaState GetState();
int GetLastError();
wxSize GetVideoSize();
protected:
DECLARE_EVENT_TABLE()
void paintEvent(wxPaintEvent &evt);
wxSize DoGetBestSize() const override;
void DoSetSize(int x, int y, int width, int height, int sizeFlags) override;
static void bambu_log(void *ctx, int level, tchar const *msg);
void PlayThread();
void NotifyStopped();
private:
wxString m_idle_image;
wxMediaState m_state = wxMEDIASTATE_STOPPED;
int m_error = 0;
wxSize m_video_size = wxDefaultSize;
wxSize m_frame_size = wxDefaultSize;
wxBitmap m_frame;
wxImage m_frame2;
std::shared_ptr<wxURI> m_url;
std::mutex m_mutex;
std::condition_variable m_cond;
std::thread m_thread;
};
#endif
#endif /* wxMediaCtrl3_h */