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}")
@ -362,7 +363,7 @@ endif()
function(slic3r_remap_configs targets from_Cfg to_Cfg)
if(MSVC)
string(TOUPPER ${from_Cfg} from_CFG)
foreach(tgt ${targets})
if(TARGET ${tgt})
set_target_properties(${tgt} PROPERTIES MAP_IMPORTED_CONFIG_${from_CFG} ${to_Cfg})
@ -503,7 +504,7 @@ add_custom_target(gettext_make_pot
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --no-location --debug --boost
-f "${BBL_L18N_DIR}/list.txt"
-o "${BBL_L18N_DIR}/BambuStudio.pot"
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${BBL_L18N_DIR}
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${BBL_L18N_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generate pot file from strings in the source tree"
)
@ -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

@ -82,7 +82,7 @@ if (SLIC3R_GUI)
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat)
list(APPEND wxWidgets_LIBRARIES ${EXPAT_LIBRARIES})
endif ()
# This is an issue in the new wxWidgets cmake build, doesn't deal with librt
find_library(LIBRT rt)
if(LIBRT)
@ -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);
@ -332,7 +333,7 @@ void MediaPlayCtrl::Play()
// !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_None (x)
if (m_lan_proto <= MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto)) {
Stop(m_lan_proto == MachineObject::LVL_None
Stop(m_lan_proto == MachineObject::LVL_None
? _L("Problem occured. Please update the printer firmware and try again.")
: _L("LAN Only Liveview is off. Please turn on the liveview on printer screen."));
return;
@ -366,7 +367,7 @@ void MediaPlayCtrl::Play()
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url,
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url,
{"?uid=", "authkey=", "passwd=", "license=", "token="});
CallAfter([this, m, url] {
if (m != m_machine) {
@ -436,7 +437,7 @@ void MediaPlayCtrl::Stop(wxString const &msg, wxString const &msg2)
auto tunnel = m_url.empty() ? "" : into_u8(wxURI(m_url).GetPath()).substr(1);
if (auto n = tunnel.find_first_of("/_"); n != std::string::npos)
tunnel = tunnel.substr(0, n);
if (last_state != wxMEDIASTATE_PLAYING && m_failed_code != 0
if (last_state != wxMEDIASTATE_PLAYING && m_failed_code != 0
&& m_last_failed_codes.find(m_failed_code) == m_last_failed_codes.end()
&& (m_user_triggered || m_failed_retry > 3)) {
json j;
@ -604,7 +605,7 @@ void MediaPlayCtrl::ToggleStream()
url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
url += "&cli_ver=" + std::string(SLIC3R_VERSION);
}
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url,
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url,
{"?uid=", "authkey=", "passwd=", "license=", "token="});
CallAfter([this, m, url] {
if (m != m_machine) return;
@ -624,8 +625,8 @@ void MediaPlayCtrl::ToggleStream()
});
}
void MediaPlayCtrl::msw_rescale() {
m_button_play->Rescale();
void MediaPlayCtrl::msw_rescale() {
m_button_play->Rescale();
}
void MediaPlayCtrl::jump_to_play()
@ -841,15 +842,15 @@ bool MediaPlayCtrl::start_stream_service(bool *need_install)
if (!boost::filesystem::exists(file_dll) || boost::filesystem::last_write_time(file_dll) != boost::filesystem::last_write_time(file_dll2))
boost::filesystem::copy_file(file_dll2, file_dll, boost::filesystem::copy_option::overwrite_if_exists);
}
boost::process::child process_source(file_source, file_url2.ToStdWstring(), boost::process::start_dir(tools_dir),
boost::process::windows::create_no_window,
boost::process::child process_source(file_source, file_url2.ToStdWstring(), boost::process::start_dir(tools_dir),
boost::process::windows::create_no_window,
boost::process::std_out > intermediate, boost::process::limit_handles);
boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::windows::create_no_window,
boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::windows::create_no_window,
boost::process::std_in < intermediate, boost::process::limit_handles);
#else
boost::filesystem::permissions(file_source, boost::filesystem::owner_exe | boost::filesystem::add_perms);
boost::filesystem::permissions(file_ffmpeg, boost::filesystem::owner_exe | boost::filesystem::add_perms);
boost::process::child process_source(file_source, file_url2.data().AsInternal(), boost::process::start_dir(start_dir),
boost::process::child process_source(file_source, file_url2.data().AsInternal(), boost::process::start_dir(start_dir),
boost::process::std_out > intermediate, boost::process::limit_handles);
boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::std_in < intermediate, boost::process::limit_handles);
#endif
@ -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;
@ -88,7 +95,7 @@ private:
bool m_device_busy = false;
bool m_disable_lan = false;
wxString m_url;
std::deque<wxString> m_tasks;
boost::mutex m_mutex;
boost::condition_variable m_cond;

View File

@ -577,7 +577,7 @@ void PrintingTaskPanel::paint(wxPaintEvent&)
dc.SetTextForeground(*wxBLACK);
dc.DrawBitmap(m_thumbnail_bmp_display, wxPoint(0, 0));
dc.SetFont(Label::Body_12);
if (m_plate_index >= 0) {
wxString plate_id_str = wxString::Format("%d", m_plate_index);
dc.DrawText(plate_id_str, wxPoint(4, 4));
@ -795,7 +795,7 @@ void PrintingTaskPanel::set_plate_index(int plate_idx)
}
void PrintingTaskPanel::market_scoring_show()
{
{
m_score_staticline->Show();
m_score_subtask_info->Show();
}
@ -916,7 +916,7 @@ void StatusBasePanel::init_bitmaps()
m_bitmap_fan_off = ScalableBitmap(this, "monitor_fan_off", 22);
m_bitmap_speed = ScalableBitmap(this, "monitor_speed", 24);
m_bitmap_speed_active = ScalableBitmap(this, "monitor_speed_active", 24);
m_thumbnail_brokenimg = ScalableBitmap(this, "monitor_brokenimg", 120);
m_thumbnail_sdcard = ScalableBitmap(this, "monitor_sdcard_thumbnail", 120);
//m_bitmap_camera = create_scaled_bitmap("monitor_camera", nullptr, 18);
@ -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)));
@ -1689,7 +1689,7 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
m_project_task_panel->get_pause_resume_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this);
m_project_task_panel->get_abort_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this);
m_project_task_panel->get_market_scoring_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this);
m_project_task_panel->get_market_retry_buttom()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this);
m_project_task_panel->get_market_retry_buttom()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this);
m_project_task_panel->get_clean_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this);
m_setting_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this);
@ -1703,7 +1703,7 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
m_switch_lamp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_lamp_switch), NULL, this);
m_switch_nozzle_fan->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this); // TODO
m_switch_printing_fan->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this);
m_switch_cham_fan->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this);
m_switch_cham_fan->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_nozzle_fan_switch), NULL, this);
m_bpButton_xy->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_xy), NULL, this); // TODO
m_bpButton_z_10->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_10), NULL, this);
m_bpButton_z_1->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_axis_ctrl_z_up_1), NULL, this);
@ -1748,7 +1748,7 @@ StatusPanel::~StatusPanel()
m_project_task_panel->get_pause_resume_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this);
m_project_task_panel->get_abort_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this);
m_project_task_panel->get_market_scoring_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this);
m_project_task_panel->get_market_retry_buttom()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this);
m_project_task_panel->get_market_retry_buttom()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_retry), NULL, this);
m_project_task_panel->get_clean_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this);
m_setting_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this);
@ -1787,7 +1787,7 @@ StatusPanel::~StatusPanel()
if (sdcard_hint_dlg != nullptr)
delete sdcard_hint_dlg;
if (m_score_data != nullptr) {
if (m_score_data != nullptr) {
delete m_score_data;
}
}
@ -1811,7 +1811,7 @@ void StatusPanel::init_scaled_buttons()
m_bpButton_e_down_10->SetCornerRadius(FromDIP(12));
}
void StatusPanel::on_market_scoring(wxCommandEvent &event) {
void StatusPanel::on_market_scoring(wxCommandEvent &event) {
if (obj && obj->is_makeworld_subtask() && obj->rating_info && obj->rating_info->request_successful) { // model is mall model and has rating_id
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_market_scoring" ;
if (m_score_data && m_score_data->rating_id == obj->rating_info->rating_id) { // current score data for model is same as mall model
@ -1820,7 +1820,7 @@ void StatusPanel::on_market_scoring(wxCommandEvent &event) {
int ret = m_score_dlg.ShowModal();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": old data";
if (ret == wxID_OK) {
if (ret == wxID_OK) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": old data is upload";
m_score_data->rating_id = -1;
m_project_task_panel->set_star_count_dirty(false);
@ -1842,11 +1842,11 @@ void StatusPanel::on_market_scoring(wxCommandEvent &event) {
std::string comment = obj->rating_info->content;
if (!comment.empty()) { m_score_dlg.set_comment(comment); }
std::vector<std::string> images_json_array;
images_json_array = obj->rating_info->image_url_paths;
if (!images_json_array.empty()) m_score_dlg.set_cloud_bitmap(images_json_array);
int ret = m_score_dlg.ShowModal();
if (ret == wxID_OK) {
@ -1881,11 +1881,11 @@ void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
if (obj->can_resume()) {
BOOST_LOG_TRIVIAL(info) << "monitor: resume current print task dev_id =" << obj->dev_id;
obj->command_task_resume();
}
}
else {
BOOST_LOG_TRIVIAL(info) << "monitor: pause current print task dev_id =" << obj->dev_id;
obj->command_task_pause();
}
}
if (m_print_error_dlg) {
m_print_error_dlg->on_hide();
}if (m_print_error_dlg_no_action) {
@ -1902,7 +1902,7 @@ void StatusPanel::on_subtask_abort(wxCommandEvent &event)
abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this](wxCommandEvent &e) {
if (obj) {
BOOST_LOG_TRIVIAL(info) << "monitor: stop current print task dev_id =" << obj->dev_id;
obj->command_task_abort();
obj->command_task_abort();
}
});
}
@ -2050,7 +2050,7 @@ void StatusPanel::update(MachineObject *obj)
calibration_dlg->update_machine_obj(obj);
calibration_dlg->update_cali(obj);
}
if (obj->is_support_first_layer_inspect
@ -2576,10 +2576,15 @@ 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);
m_ams_control->show_auto_refill(true);
m_ams_control->show_auto_refill(true);
}
@ -2643,7 +2648,7 @@ void StatusPanel::update_ams(MachineObject *obj)
m_ams_control->SetExtruder(obj->is_filament_at_extruder(), true, obj->m_ams_id, obj->vt_tray.get_color());
} else {
m_ams_control->SetExtruder(obj->is_filament_at_extruder(), false, obj->m_ams_id, m_ams_control->GetCanColour(obj->m_ams_id, obj->m_tray_id));
}
if (obj->ams_status_main == AMS_STATUS_MAIN_FILAMENT_CHANGE) {
@ -2696,7 +2701,7 @@ void StatusPanel::update_ams(MachineObject *obj)
}else{
m_ams_control->SetFilamentStep(FilamentStep::STEP_PUSH_NEW_FILAMENT, FilamentStepType::STEP_TYPE_LOAD);
}
}
else {
m_ams_control->SetFilamentStep(FilamentStep::STEP_PUSH_NEW_FILAMENT, FilamentStepType::STEP_TYPE_UNLOAD);
@ -2736,7 +2741,7 @@ void StatusPanel::update_ams(MachineObject *obj)
} else {
m_ams_control->SetFilamentStep(FilamentStep::STEP_IDLE, FilamentStepType::STEP_TYPE_LOAD);
}
for (auto ams_it = obj->amsList.begin(); ams_it != obj->amsList.end(); ams_it++) {
std::string ams_id = ams_it->first;
@ -2783,7 +2788,7 @@ void StatusPanel::update_ams(MachineObject *obj)
}else {
is_curr_tray_selected = true;
}
update_ams_control_state(is_curr_tray_selected);
}
@ -2839,7 +2844,7 @@ void StatusPanel::update_ams_control_state(bool is_curr_tray_selected)
if (!obj->is_filament_at_extruder()) {
enable[ACTION_BTN_UNLOAD] = false;
}
if (obj->ams_exist_bits == 0) {
if (obj->is_in_printing()) {
if (!obj->can_resume()) {
@ -2857,7 +2862,7 @@ void StatusPanel::update_ams_control_state(bool is_curr_tray_selected)
}
}
}
}
else {
if (obj->is_in_printing() /*&& obj->can_resume() && obj->m_tray_now != std::to_string(VIRTUAL_TRAY_ID) */) {
@ -2876,7 +2881,7 @@ void StatusPanel::update_ams_control_state(bool is_curr_tray_selected)
else if (!m_ams_control->GetCurrentCan(m_ams_control->GetCurentAms()).empty()) {
enable[ACTION_BTN_LOAD] = false;
enable[ACTION_BTN_UNLOAD] = false;
}
}
}
else if (obj->m_tray_now == std::to_string(VIRTUAL_TRAY_ID)) {
if (m_ams_control->GetCurentAms() == std::to_string(VIRTUAL_TRAY_ID)) {
@ -2892,7 +2897,7 @@ void StatusPanel::update_ams_control_state(bool is_curr_tray_selected)
enable[ACTION_BTN_LOAD] = false;
enable[ACTION_BTN_UNLOAD] = false;
}
}
}
}
}
@ -2952,14 +2957,14 @@ void StatusPanel::update_basic_print_data(bool def)
void StatusPanel::update_model_info()
{
auto get_subtask_fn = [this](BBLModelTask* subtask) {
CallAfter([this, subtask]() {
CallAfter([this, subtask]() {
if (obj && obj->subtask_id_ == subtask->task_id) {
obj->set_modeltask(subtask);
}
});
};
if (wxGetApp().getAgent() && obj) {
BBLSubTask* curr_task = obj->get_subtask();
if (curr_task) {
@ -3024,7 +3029,7 @@ void StatusPanel::update_subtask(MachineObject *obj)
if (calib_bitmap != nullptr)
m_project_task_panel->set_thumbnail_img(*calib_bitmap);
}
if (obj->is_support_layer_num) {
m_project_task_panel->update_layers_num(true);
}
@ -3127,7 +3132,7 @@ void StatusPanel::update_subtask(MachineObject *obj)
m_project_task_panel->get_request_failed_panel()->Hide();
}
// update printing stage
m_project_task_panel->update_left_time(obj->mc_left_time);
if (obj->subtask_) {
m_project_task_panel->update_stage_value(obj->get_curr_stage(), obj->subtask_->task_progress);
@ -3243,7 +3248,7 @@ void StatusPanel::reset_printing_values()
m_project_task_panel->update_left_time(NA_STR);
m_project_task_panel->update_layers_num(true, wxString::Format(_L("Layer: %s"), NA_STR));
update_calib_bitmap();
task_thumbnail_state = ThumbnailState::PLACE_HOLDER;
m_start_loading_thumbnail = false;
m_load_sdcard_thumbnail = false;
@ -3313,7 +3318,7 @@ bool StatusPanel::check_axis_z_at_home(MachineObject* obj)
}
void StatusPanel::on_axis_ctrl_z_up_10(wxCommandEvent &event)
{
{
if (obj) {
obj->command_axis_control("Z", 1.0, -10.0f, 900);
if (!check_axis_z_at_home(obj))
@ -3478,7 +3483,7 @@ void StatusPanel::on_ams_load_curr()
std::string curr_ams_id = m_ams_control->GetCurentAms();
std::string curr_can_id = m_ams_control->GetCurrentCan(curr_ams_id);
update_filament_step();
//virtual tray
if (curr_ams_id.compare(std::to_string(VIRTUAL_TRAY_ID)) == 0) {
@ -3853,7 +3858,7 @@ void StatusPanel::on_ams_guide(wxCommandEvent& event)
else {
ams_wiki_url = "https://wiki.bambulab.com/en/software/bambu-studio/use-ams-on-bambu-studio";
}
wxLaunchDefaultBrowser(ams_wiki_url);
}
@ -3991,7 +3996,7 @@ void StatusPanel::on_switch_speed(wxCommandEvent &event)
speed_dismiss_time = boost::posix_time::microsec_clock::universal_time();
}
});
m_ams_control->Bind(EVT_CLEAR_SPEED_CONTROL, [this, popUp](auto& e) {
if (m_showing_speed_popup) {
if (popUp && popUp->IsShown()) {
@ -4378,8 +4383,8 @@ void StatusPanel::msw_rescale()
m_calibration_btn->Rescale();
m_options_btn->SetMinSize(wxSize(-1, FromDIP(26)));
m_options_btn->Rescale();
m_options_btn->Rescale();
m_parts_btn->SetMinSize(wxSize(-1, FromDIP(26)));
m_parts_btn->Rescale();
@ -4420,11 +4425,11 @@ ScoreDialog::ScoreDialog(wxWindow *parent, ScoreData *score_data)
, m_upload_status_code(StatusCode::CODE_NUMBER)
{
m_tocken.reset(new int(0));
wxBoxSizer *m_main_sizer = get_main_sizer(score_data->local_to_url_image, score_data->comment_text);
m_image_url_paths = score_data->image_url_paths;
this->SetSizer(m_main_sizer);
Fit();
@ -4440,16 +4445,16 @@ void ScoreDialog::on_dpi_changed(const wxRect &suggested_rect) {}
void ScoreDialog::OnBitmapClicked(wxMouseEvent &event)
{
wxStaticBitmap *clickedBitmap = dynamic_cast<wxStaticBitmap *>(event.GetEventObject());
if (m_image.find(clickedBitmap) != m_image.end()) {
if (m_image.find(clickedBitmap) != m_image.end()) {
if (!m_image[clickedBitmap].is_selected) {
for (auto panel : m_image[clickedBitmap].image_broad) {
for (auto panel : m_image[clickedBitmap].image_broad) {
panel->Show();
}
m_image[clickedBitmap].is_selected = true;
m_selected_image_list.insert(clickedBitmap);
} else {
for (auto panel : m_image[clickedBitmap].image_broad) {
panel->Hide();
for (auto panel : m_image[clickedBitmap].image_broad) {
panel->Hide();
}
m_image[clickedBitmap].is_selected = false;
m_selected_image_list.erase(clickedBitmap);
@ -4466,9 +4471,9 @@ void ScoreDialog::OnBitmapClicked(wxMouseEvent &event)
}
std::set <std::pair<wxStaticBitmap * ,wxString>> ScoreDialog::add_need_upload_imgs()
{
{
std::set<std::pair<wxStaticBitmap *, wxString>> need_upload_images;
for (auto bitmap : m_image) {
for (auto bitmap : m_image) {
if (!bitmap.second.is_uploaded) {
wxString &local_image_path = bitmap.second.local_image_url;
if (!local_image_path.empty()) { need_upload_images.insert(std::make_pair(bitmap.first, local_image_path)); }
@ -4488,7 +4493,7 @@ std::pair<wxStaticBitmap *, ScoreDialog::ImageMsg> ScoreDialog::create_local_thu
cur_image_msg.local_image_url = local_path;
cur_image_msg.img_url_paths = "";
cur_image_msg.is_uploaded = false;
wxStaticBitmap *imageCtrl = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxImage(local_path, wxBITMAP_TYPE_ANY).Rescale(FromDIP(80), FromDIP(60))), wxDefaultPosition,
wxDefaultSize, 0);
imageCtrl->Bind(wxEVT_LEFT_DOWN, &ScoreDialog::OnBitmapClicked, this);
@ -4553,7 +4558,7 @@ void ScoreDialog::update_static_bitmap(wxStaticBitmap* static_bitmap, wxImage im
}
wxBoxSizer *ScoreDialog::create_broad_sizer(wxStaticBitmap *bitmap, ImageMsg& cur_image_msg)
{
{
// tb: top and bottom lr: left and right
auto m_image_tb_broad = new wxBoxSizer(wxVERTICAL);
auto line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
@ -4600,7 +4605,7 @@ void ScoreDialog::init() {
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
}
wxBoxSizer *ScoreDialog::get_score_sizer() {
wxBoxSizer *ScoreDialog::get_score_sizer() {
wxBoxSizer *score_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *static_score_text = new wxStaticText(this, wxID_ANY, _L("Rate"), wxDefaultPosition, wxDefaultSize, 0);
static_score_text->Wrap(-1);
@ -4720,18 +4725,18 @@ wxBoxSizer *ScoreDialog::get_photo_btn_sizer() {
for (int i = 0; i < filePaths.GetCount(); i++) { //It's ugly, but useful
bool is_repeat = false;
for (auto image : m_image) {
if (filePaths[i] == image.second.local_image_url) {
if (filePaths[i] == image.second.local_image_url) {
is_repeat = true;
continue;
}
}
if (!is_repeat) {
local_path.push_back(std::make_pair(filePaths[i], ""));
if (local_path.size() + m_image.size() > m_photo_nums) {
break;
if (local_path.size() + m_image.size() > m_photo_nums) {
break;
}
}
}
load_photo(local_path);
@ -4858,7 +4863,7 @@ wxBoxSizer *ScoreDialog::get_button_sizer()
}
}
progress_dialog->Hide();
if (progress_dialog) {
if (progress_dialog) {
delete progress_dialog;
progress_dialog = nullptr;
}
@ -4998,7 +5003,7 @@ wxBoxSizer *ScoreDialog::get_main_sizer(const std::vector<std::pair<wxString, st
m_main_sizer->Add(m_photo_sizer, 0, wxEXPAND | wxTOP, FromDIP(8));
m_image_sizer = new wxGridSizer(5, FromDIP(5), FromDIP(5));
if (!images.empty()) {
if (!images.empty()) {
load_photo(images);
}
m_main_sizer->Add(m_image_sizer, 0, wxEXPAND | wxLEFT, FromDIP(24));
@ -5010,7 +5015,7 @@ wxBoxSizer *ScoreDialog::get_main_sizer(const std::vector<std::pair<wxString, st
return m_main_sizer;
}
ScoreData ScoreDialog::get_score_data() {
ScoreData ScoreDialog::get_score_data() {
ScoreData score_data;
score_data.rating_id = m_rating_id;
score_data.design_id = m_design_id;
@ -5021,20 +5026,20 @@ ScoreData ScoreDialog::get_score_data() {
score_data.comment_text = m_comment_text->GetValue();
score_data.image_url_paths = m_image_url_paths;
for (auto img : m_image) { score_data.local_to_url_image.push_back(std::make_pair(img.second.local_image_url, img.second.img_url_paths)); }
return score_data;
}
void ScoreDialog::set_comment(std::string comment)
{
if (m_comment_text) {
if (m_comment_text) {
m_comment_text->SetValue(wxString::FromUTF8(comment));
}
}
void ScoreDialog::set_cloud_bitmap(std::vector<std::string> cloud_bitmaps)
{
{
m_image_url_paths = cloud_bitmaps;
for (std::string &url : cloud_bitmaps) {
if (std::string::npos == url.find(m_model_id)) continue;

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"
@ -91,11 +90,11 @@ public:
void set_cloud_bitmap(std::vector<std::string> cloud_bitmaps);
protected:
enum StatusCode {
UPLOAD_PROGRESS = 0,
UPLOAD_EXIST_ISSUE,
enum StatusCode {
UPLOAD_PROGRESS = 0,
UPLOAD_EXIST_ISSUE,
UPLOAD_IMG_FAILED,
CODE_NUMBER
CODE_NUMBER
};
std::shared_ptr<int> m_tocken;
@ -113,7 +112,7 @@ protected:
{
wxString local_image_url; //local image path
std::string img_url_paths; // oss url path
vector<wxPanel *> image_broad;
vector<wxPanel *> image_broad;
bool is_selected;
bool is_uploaded; // load
wxBoxSizer * image_tb_broad = nullptr;
@ -148,7 +147,7 @@ protected:
std::set<std::pair<wxStaticBitmap *, wxString>> add_need_upload_imgs();
std::pair<wxStaticBitmap *, ImageMsg> create_local_thumbnail(wxString &local_path);
std::pair<wxStaticBitmap *, ImageMsg> create_oss_thumbnail(std::string &oss_path);
};
class PrintingTaskPanel : public wxPanel
@ -157,7 +156,7 @@ public:
PrintingTaskPanel(wxWindow* parent, PrintingTaskType type);
~PrintingTaskPanel();
void create_panel(wxWindow* parent);
private:
MachineObject* m_obj;
@ -232,7 +231,7 @@ public:
void set_plate_index(int plate_idx = -1);
void market_scoring_show();
void market_scoring_hide();
public:
ScalableButton* get_abort_button() {return m_button_abort;};
ScalableButton* get_pause_resume_button() {return m_button_pause_resume;};
@ -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;
@ -340,7 +339,7 @@ protected:
/* TempInput */
wxBoxSizer * m_misc_ctrl_sizer;
StaticBox* m_fan_panel;
StaticBox* m_fan_panel;
StaticLine * m_line_nozzle;
TempInput* m_tempCtrl_nozzle;
int m_temp_nozzle_timeout{ 0 };
@ -406,7 +405,7 @@ protected:
virtual void on_bed_temp_kill_focus(wxFocusEvent &event) { event.Skip(); }
virtual void on_bed_temp_set_focus(wxFocusEvent &event) { event.Skip(); }
virtual void on_nozzle_temp_kill_focus(wxFocusEvent &event) { event.Skip(); }
virtual void on_nozzle_temp_set_focus(wxFocusEvent &event) { event.Skip(); }
virtual void on_nozzle_temp_set_focus(wxFocusEvent &event) { event.Skip(); }
virtual void on_nozzle_fan_switch(wxCommandEvent &event) { event.Skip(); }
virtual void on_printing_fan_switch(wxCommandEvent &event) { event.Skip(); }
virtual void on_axis_ctrl_z_up_10(wxCommandEvent &event) { event.Skip(); }

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>
@ -61,8 +61,8 @@ void wxMediaCtrl2::Load(wxURI url)
if (!notified) CallAfter([] {
auto res = wxMessageBox(_L("Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?"), _L("Error"), wxOK | wxCANCEL);
if (res == wxOK) {
wxString url = IsWindows10OrGreater()
? "ms-settings:optionalfeatures?activationSource=SMC-Article-14209"
wxString url = IsWindows10OrGreater()
? "ms-settings:optionalfeatures?activationSource=SMC-Article-14209"
: "https://support.microsoft.com/en-au/windows/get-windows-media-player-81718e0d-cfce-25b1-aee3-94596b658287";
wxExecute("cmd /c start " + url, wxEXEC_HIDE_CONSOLE);
}
@ -77,7 +77,7 @@ void wxMediaCtrl2::Load(wxURI url)
{
wxRegKey key11(wxRegKey::HKCU, L"SOFTWARE\\Classes\\CLSID\\" CLSID_BAMBU_SOURCE L"\\InProcServer32");
wxRegKey key12(wxRegKey::HKCR, L"CLSID\\" CLSID_BAMBU_SOURCE L"\\InProcServer32");
wxString path = key11.Exists() ? key11.QueryDefaultValue()
wxString path = key11.Exists() ? key11.QueryDefaultValue()
: key12.Exists() ? key12.QueryDefaultValue() : wxString{};
wxRegKey key2(wxRegKey::HKCR, "bambu");
wxString clsid;
@ -144,14 +144,14 @@ void wxMediaCtrl2::Load(wxURI url)
#ifdef __WXGTK3__
GstElementFactory *factory;
int hasplugins = 1;
factory = gst_element_factory_find("h264parse");
if (!factory) {
hasplugins = 0;
} else {
gst_object_unref(factory);
}
factory = gst_element_factory_find("openh264dec");
if (!factory) {
factory = gst_element_factory_find("avdec_h264");
@ -164,7 +164,7 @@ void wxMediaCtrl2::Load(wxURI url)
} else {
gst_object_unref(factory);
}
if (!hasplugins) {
CallAfter([] {
wxMessageBox(_L("Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Bambu Studio?)"), _L("Error"), wxOK);
@ -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,13 +13,15 @@
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
{
public:
wxMediaCtrl2(wxWindow * parent);
~wxMediaCtrl2();
void Load(wxURI url);
@ -41,8 +43,8 @@ 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();
private:

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 */