2022-07-15 15:37:19 +00:00
|
|
|
#include "MediaPlayCtrl.h"
|
|
|
|
#include "Widgets/Button.hpp"
|
|
|
|
#include "Widgets/CheckBox.hpp"
|
|
|
|
#include "Widgets/Label.hpp"
|
|
|
|
#include "GUI_App.hpp"
|
|
|
|
#include "libslic3r/AppConfig.hpp"
|
|
|
|
#include "I18N.hpp"
|
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
namespace GUI {
|
|
|
|
|
|
|
|
MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const wxPoint &pos, const wxSize &size)
|
|
|
|
: wxPanel(parent, wxID_ANY, pos, size)
|
|
|
|
, m_media_ctrl(media_ctrl)
|
|
|
|
{
|
|
|
|
SetBackgroundColour(*wxWHITE);
|
|
|
|
m_media_ctrl->Bind(wxEVT_MEDIA_STATECHANGED, &MediaPlayCtrl::onStateChanged, this);
|
|
|
|
|
|
|
|
m_button_play = new Button(this, "", "media_play", wxBORDER_NONE);
|
|
|
|
|
|
|
|
m_label_status = new Label(Label::Body_14, this);
|
|
|
|
|
|
|
|
m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto & e) { TogglePlay(); });
|
|
|
|
|
|
|
|
m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) { m_media_ctrl->Play(); });
|
|
|
|
|
|
|
|
Bind(wxEVT_RIGHT_UP, [this](auto & e) { wxClipboard & c = *wxTheClipboard; if (c.Open()) { c.SetData(new wxTextDataObject(m_url)); c.Close(); } });
|
|
|
|
|
|
|
|
wxBoxSizer * sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
sizer->Add(m_button_play, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 0);
|
|
|
|
sizer->AddStretchSpacer(1);
|
|
|
|
sizer->Add(m_label_status, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(25));
|
|
|
|
SetSizer(sizer);
|
|
|
|
|
|
|
|
m_thread = boost::thread([this] {
|
|
|
|
media_proc();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaPlayCtrl::~MediaPlayCtrl()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
boost::unique_lock lock(m_mutex);
|
|
|
|
m_tasks.push_back("<exit>");
|
|
|
|
m_cond.notify_all();
|
|
|
|
}
|
|
|
|
m_thread.join();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::SetMachineObject(MachineObject* obj)
|
|
|
|
{
|
|
|
|
std::string machine = obj ? obj->dev_id : "";
|
|
|
|
if (machine == m_machine) {
|
|
|
|
if (m_last_state == MEDIASTATE_IDLE && m_next_retry.IsValid() && wxDateTime::Now() >= m_next_retry)
|
|
|
|
Play();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_machine = machine;
|
|
|
|
m_failed_retry = 0;
|
|
|
|
if (m_last_state != MEDIASTATE_IDLE)
|
|
|
|
Stop();
|
|
|
|
//Play();
|
|
|
|
SetStatus("");
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::Play()
|
|
|
|
{
|
|
|
|
if (m_machine.empty()) {
|
|
|
|
SetStatus(_L("Initialize failed (No Device)!"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_last_state != MEDIASTATE_IDLE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_last_state = MEDIASTATE_INITIALIZING;
|
|
|
|
m_button_play->SetIcon("media_stop");
|
|
|
|
SetStatus(_L("Initializing..."));
|
|
|
|
|
|
|
|
|
|
|
|
NetworkAgent* agent = wxGetApp().getAgent();
|
|
|
|
if (agent) {
|
|
|
|
agent->get_camera_url(m_machine, [this](std::string url) {
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "camera_url: " << url;
|
|
|
|
CallAfter([this, url] {
|
|
|
|
m_url = url;
|
|
|
|
if (m_last_state == MEDIASTATE_INITIALIZING) {
|
|
|
|
if (url.empty()) {
|
|
|
|
Stop();
|
|
|
|
m_failed_code = 1;
|
|
|
|
SetStatus(_L("Initialize failed [%d]!"));
|
|
|
|
} else {
|
|
|
|
m_last_state = MEDIASTATE_LOADING;
|
|
|
|
SetStatus(_L("Loading..."));
|
|
|
|
if (wxGetApp().app_config->get("dump_video") == "true") {
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << boost::filesystem::current_path();
|
|
|
|
m_url = m_url + "&dump=video.h264";
|
|
|
|
}
|
|
|
|
boost::unique_lock lock(m_mutex);
|
|
|
|
m_tasks.push_back(m_url);
|
|
|
|
m_cond.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::Stop()
|
|
|
|
{
|
|
|
|
if (m_last_state != MEDIASTATE_IDLE) {
|
|
|
|
m_media_ctrl->InvalidateBestSize();
|
|
|
|
m_button_play->SetIcon("media_play");
|
|
|
|
boost::unique_lock lock(m_mutex);
|
2022-07-22 09:46:10 +00:00
|
|
|
m_tasks.push_back("<stop>");
|
2022-07-15 15:37:19 +00:00
|
|
|
m_cond.notify_all();
|
|
|
|
}
|
|
|
|
m_last_state = MEDIASTATE_IDLE;
|
|
|
|
SetStatus(_L("Stopped."));
|
|
|
|
++m_failed_retry;
|
|
|
|
//m_next_retry = wxDateTime::Now() + wxTimeSpan::Seconds(5 * m_failed_retry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::TogglePlay()
|
|
|
|
{
|
|
|
|
if (m_last_state != MEDIASTATE_IDLE)
|
|
|
|
Stop();
|
|
|
|
else
|
|
|
|
Play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::SetStatus(wxString const& msg2)
|
|
|
|
{
|
|
|
|
auto msg = wxString::Format(msg2, m_failed_code);
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::SetStatus: " << msg.ToUTF8().data();
|
2022-07-22 09:46:10 +00:00
|
|
|
#ifdef __WXMSW__
|
|
|
|
OutputDebugStringA("MediaPlayCtrl::SetStatus: ");
|
|
|
|
OutputDebugStringA(msg.ToUTF8().data());
|
|
|
|
OutputDebugStringA("\n");
|
|
|
|
#endif // __WXMSW__
|
2022-07-15 15:37:19 +00:00
|
|
|
m_label_status->SetLabel(msg);
|
|
|
|
//m_label_status->SetForegroundColour(!msg.EndsWith("!") ? 0x42AE00 : 0x3B65E9);
|
|
|
|
Layout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::media_proc()
|
|
|
|
{
|
|
|
|
boost::unique_lock lock(m_mutex);
|
|
|
|
while (true) {
|
|
|
|
while (m_tasks.empty()) {
|
|
|
|
m_cond.wait(lock);
|
|
|
|
}
|
|
|
|
wxString url = m_tasks.front();
|
|
|
|
lock.unlock();
|
|
|
|
if (url.IsEmpty()) {
|
2022-07-22 09:46:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (url == "<stop>") {
|
2022-07-15 15:37:19 +00:00
|
|
|
m_media_ctrl->Stop();
|
|
|
|
}
|
|
|
|
else if (url == "<exit>") {
|
|
|
|
break;
|
|
|
|
}
|
2022-07-22 09:46:10 +00:00
|
|
|
else if (url == "<play>") {
|
|
|
|
m_media_ctrl->Play();
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
else {
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: start load";
|
|
|
|
m_media_ctrl->Load(wxURI(url));
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: end load";
|
|
|
|
}
|
|
|
|
lock.lock();
|
|
|
|
m_tasks.pop_front();
|
|
|
|
wxMediaEvent theEvent(wxEVT_MEDIA_STATECHANGED, m_media_ctrl->GetId());
|
|
|
|
theEvent.SetId(0);
|
|
|
|
m_media_ctrl->GetEventHandler()->AddPendingEvent(theEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaPlayCtrl::onStateChanged(wxMediaEvent& event)
|
|
|
|
{
|
|
|
|
auto last_state = m_last_state;
|
|
|
|
auto state = m_media_ctrl->GetState();
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: " << state << ", last_state: " << last_state;
|
|
|
|
if ((int) state < 0)
|
|
|
|
return;
|
|
|
|
{
|
|
|
|
boost::unique_lock lock(m_mutex);
|
|
|
|
if (!m_tasks.empty()) {
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: skip when task not finished";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (last_state == MEDIASTATE_IDLE && state == wxMEDIASTATE_STOPPED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_last_state = state;
|
|
|
|
if ((last_state == wxMEDIASTATE_PAUSED || last_state == wxMEDIASTATE_PLAYING) &&
|
|
|
|
state == wxMEDIASTATE_STOPPED) {
|
|
|
|
Stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (last_state == MEDIASTATE_LOADING && state == wxMEDIASTATE_STOPPED) {
|
|
|
|
wxSize size = m_media_ctrl->GetVideoSize();
|
|
|
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: size: " << size.x << "x" << size.y;
|
|
|
|
m_failed_code = m_media_ctrl->GetLastError();
|
|
|
|
if (size.GetWidth() > 1000) {
|
|
|
|
SetStatus(_L("Playing..."));
|
|
|
|
m_failed_retry = 0;
|
2022-07-22 09:46:10 +00:00
|
|
|
boost::unique_lock lock(m_mutex);
|
|
|
|
m_tasks.push_back("<play>");
|
|
|
|
m_cond.notify_all();
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
else if (event.GetId()) {
|
|
|
|
Stop();
|
|
|
|
SetStatus(_L("Load failed [%d]!"));
|
|
|
|
} else {
|
|
|
|
m_last_state = last_state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
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;
|
|
|
|
wxSize size = GetVideoSize();
|
|
|
|
if (size.GetWidth() <= 0)
|
|
|
|
size = wxSize{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});
|
|
|
|
Slic3r::GUI::wxGetApp().CallAfter([this] {
|
|
|
|
GetParent()->Layout();
|
|
|
|
GetParent()->Refresh();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|