mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
feat: use ffmpeg to render http camera stream
This commit is contained in:
Vendored
+2
-2
@@ -69,14 +69,14 @@ else ()
|
|||||||
--disable-filters
|
--disable-filters
|
||||||
--enable-filter=*null*,afade,*fifo,*format,*resample,aeval,allrgb,allyuv,atempo,pan,*bars,color,*key,crop,draw*,eq*,framerate,*_qsv,*_vaapi,*v4l2*,hw*,scale,volume,test*
|
--enable-filter=*null*,afade,*fifo,*format,*resample,aeval,allrgb,allyuv,atempo,pan,*bars,color,*key,crop,draw*,eq*,framerate,*_qsv,*_vaapi,*v4l2*,hw*,scale,volume,test*
|
||||||
--disable-protocols
|
--disable-protocols
|
||||||
--enable-protocol=file,fd,pipe,rtp,tcp,udp
|
--enable-protocol=file,fd,pipe,http,rtp,tcp,udp
|
||||||
--disable-muxers
|
--disable-muxers
|
||||||
--enable-muxer=rtp
|
--enable-muxer=rtp
|
||||||
--disable-encoders
|
--disable-encoders
|
||||||
--disable-decoders
|
--disable-decoders
|
||||||
--enable-decoder=*aac*,h264*,mp3*,mjpeg,rv*
|
--enable-decoder=*aac*,h264*,mp3*,mjpeg,rv*
|
||||||
--disable-demuxers
|
--disable-demuxers
|
||||||
--enable-demuxer=h264,mp3,mov,rtsp,sdp
|
--enable-demuxer=h264,mp3,mov,mpjpeg,rtsp,sdp
|
||||||
--disable-zlib
|
--disable-zlib
|
||||||
--disable-avdevice
|
--disable-avdevice
|
||||||
BUILD_IN_SOURCE ON
|
BUILD_IN_SOURCE ON
|
||||||
|
|||||||
@@ -290,7 +290,6 @@ void refresh_agora_url(char const* device, char const* dev_ver, char const* chan
|
|||||||
void MediaPlayCtrl::Play()
|
void MediaPlayCtrl::Play()
|
||||||
{
|
{
|
||||||
switch (current_mode()) {
|
switch (current_mode()) {
|
||||||
case CameraStreamMode::http:
|
|
||||||
case CameraStreamMode::http_snapshot:
|
case CameraStreamMode::http_snapshot:
|
||||||
if (!m_next_retry.IsValid() || wxDateTime::Now() < m_next_retry)
|
if (!m_next_retry.IsValid() || wxDateTime::Now() < m_next_retry)
|
||||||
return;
|
return;
|
||||||
@@ -300,14 +299,13 @@ void MediaPlayCtrl::Play()
|
|||||||
Stop(_L("Please confirm if the printer is connected."));
|
Stop(_L("Please confirm if the printer is connected."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (auto agent = wxGetApp().getAgent())
|
|
||||||
agent->command_start_camera(m_machine);
|
|
||||||
m_button_play->SetIcon("media_stop");
|
m_button_play->SetIcon("media_stop");
|
||||||
m_web_ctrl->Load(wxURI(m_url), current_mode());
|
m_web_ctrl->Load(wxURI(m_url), current_mode());
|
||||||
m_web_ctrl->Play();
|
m_web_ctrl->Play();
|
||||||
m_last_state = wxMEDIASTATE_PLAYING;
|
m_last_state = wxMEDIASTATE_PLAYING;
|
||||||
SetStatus(_L("Playing..."), false);
|
SetStatus(_L("Playing..."), false);
|
||||||
return;
|
return;
|
||||||
|
case CameraStreamMode::http:
|
||||||
case CameraStreamMode::rtsp:
|
case CameraStreamMode::rtsp:
|
||||||
if (m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry)
|
if (m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry)
|
||||||
return;
|
return;
|
||||||
@@ -769,7 +767,8 @@ void MediaPlayCtrl::load()
|
|||||||
{
|
{
|
||||||
m_last_state = MEDIASTATE_LOADING;
|
m_last_state = MEDIASTATE_LOADING;
|
||||||
SetStatus(_L("Loading..."));
|
SetStatus(_L("Loading..."));
|
||||||
if (current_mode() != CameraStreamMode::rtsp) {
|
const auto mode = current_mode();
|
||||||
|
if (mode != CameraStreamMode::rtsp && mode != CameraStreamMode::http) {
|
||||||
std::string file_h264 = data_dir() + "/video.h264";
|
std::string file_h264 = data_dir() + "/video.h264";
|
||||||
std::string file_info = data_dir() + "/video.info";
|
std::string file_info = data_dir() + "/video.info";
|
||||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << file_h264;
|
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << file_h264;
|
||||||
|
|||||||
@@ -2308,8 +2308,8 @@ void StatusPanel::update_camera_state(MachineObject* obj)
|
|||||||
|
|
||||||
auto agent = wxGetApp().getAgent();
|
auto agent = wxGetApp().getAgent();
|
||||||
const auto camera_mode = agent ? agent->get_camera_stream_mode() : CameraStreamMode::none;
|
const auto camera_mode = agent ? agent->get_camera_stream_mode() : CameraStreamMode::none;
|
||||||
const bool has_printer_webcam = camera_mode == CameraStreamMode::http || camera_mode == CameraStreamMode::http_snapshot;
|
const bool use_webview = camera_mode == CameraStreamMode::http_snapshot;
|
||||||
if (has_printer_webcam) {
|
if (use_webview) {
|
||||||
//m_camera_switch_button->Hide();
|
//m_camera_switch_button->Hide();
|
||||||
if (!m_custom_camera_view->IsShown()) {
|
if (!m_custom_camera_view->IsShown()) {
|
||||||
// why: do not reload the WebView URL per tick, or redirects can cause a reload loop.
|
// why: do not reload the WebView URL per tick, or redirects can cause a reload loop.
|
||||||
@@ -2317,11 +2317,15 @@ void StatusPanel::update_camera_state(MachineObject* obj)
|
|||||||
m_custom_camera_view->Show();
|
m_custom_camera_view->Show();
|
||||||
m_media_ctrl->Hide();
|
m_media_ctrl->Hide();
|
||||||
}
|
}
|
||||||
} else if (m_custom_camera_view->IsShown()) {
|
} else {
|
||||||
|
if (m_custom_camera_view->IsShown()) {
|
||||||
m_custom_camera_view->Hide();
|
m_custom_camera_view->Hide();
|
||||||
m_media_ctrl->Show();
|
// Stop the snapshot WebView before switching to native playback
|
||||||
|
// or leaving the camera mode.
|
||||||
m_media_play_ctrl->StopWebStream();
|
m_media_play_ctrl->StopWebStream();
|
||||||
}
|
}
|
||||||
|
m_media_ctrl->Show();
|
||||||
|
}
|
||||||
|
|
||||||
//sdcard
|
//sdcard
|
||||||
auto sdcard_state = obj->GetStorage()->get_sdcard_state();
|
auto sdcard_state = obj->GetStorage()->get_sdcard_state();
|
||||||
@@ -2354,7 +2358,7 @@ void StatusPanel::update_camera_state(MachineObject* obj)
|
|||||||
m_last_recording = obj->is_recording() ? 1 : 0;
|
m_last_recording = obj->is_recording() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_printer_webcam) {
|
if (use_webview) {
|
||||||
if (m_bitmap_recording_img->IsShown()) {
|
if (m_bitmap_recording_img->IsShown()) {
|
||||||
m_bitmap_recording_img->Hide();
|
m_bitmap_recording_img->Hide();
|
||||||
m_panel_monitoring_title->Layout();
|
m_panel_monitoring_title->Layout();
|
||||||
@@ -2417,7 +2421,7 @@ void StatusPanel::update_camera_state(MachineObject* obj)
|
|||||||
m_camera_popup->update(show_vcamera);
|
m_camera_popup->update(show_vcamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_setting_button->Show(!has_printer_webcam);
|
m_setting_button->Show(!use_webview);
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name)
|
StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name)
|
||||||
|
|||||||
@@ -188,14 +188,14 @@ void wxMediaCtrl3::bambu_log(void *ctx, int level, tchar const *msg2)
|
|||||||
BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
|
BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxMediaCtrl3::rtsp_interrupt_callback(void *opaque)
|
int wxMediaCtrl3::ffmpeg_interrupt_callback(void *opaque)
|
||||||
{
|
{
|
||||||
auto *ctrl = static_cast<wxMediaCtrl3 *>(opaque);
|
auto *ctrl = static_cast<wxMediaCtrl3 *>(opaque);
|
||||||
std::lock_guard<std::mutex> lock(ctrl->m_mutex);
|
std::lock_guard<std::mutex> lock(ctrl->m_mutex);
|
||||||
return ctrl->m_url != ctrl->m_active_url;
|
return ctrl->m_url != ctrl->m_active_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxMediaCtrl3::PlayRtsp(std::shared_ptr<wxURI> const &url, std::unique_lock<std::mutex> &lock)
|
int wxMediaCtrl3::PlayFfmpeg(std::shared_ptr<wxURI> const &url, std::unique_lock<std::mutex> &lock)
|
||||||
{
|
{
|
||||||
if (avformat_network_init() < 0)
|
if (avformat_network_init() < 0)
|
||||||
return 2;
|
return 2;
|
||||||
@@ -206,7 +206,9 @@ int wxMediaCtrl3::PlayRtsp(std::shared_ptr<wxURI> const &url, std::unique_lock<s
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
format_context->interrupt_callback = {&wxMediaCtrl3::rtsp_interrupt_callback, this};
|
format_context->interrupt_callback = {&wxMediaCtrl3::ffmpeg_interrupt_callback, this};
|
||||||
|
format_context->flags |= AVFMT_FLAG_NOBUFFER;
|
||||||
|
format_context->max_delay = 0;
|
||||||
m_active_url = url;
|
m_active_url = url;
|
||||||
|
|
||||||
auto finish = [&](int error) {
|
auto finish = [&](int error) {
|
||||||
@@ -219,8 +221,20 @@ int wxMediaCtrl3::PlayRtsp(std::shared_ptr<wxURI> const &url, std::unique_lock<s
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::string uri = url->BuildURI().ToUTF8().data();
|
const std::string uri = url->BuildURI().ToUTF8().data();
|
||||||
|
const wxString scheme = url->GetScheme();
|
||||||
|
const bool http_stream = scheme.CmpNoCase("http") == 0 || scheme.CmpNoCase("https") == 0;
|
||||||
AVDictionary *options = nullptr;
|
AVDictionary *options = nullptr;
|
||||||
|
if (http_stream) {
|
||||||
|
// This is a live multipart MJPEG stream. Keep FFmpeg from building a
|
||||||
|
// read-ahead buffer, otherwise the UI can display frames several
|
||||||
|
// seconds behind the camera.
|
||||||
|
av_dict_set(&options, "fflags", "nobuffer", 0);
|
||||||
|
av_dict_set(&options, "avioflags", "direct", 0);
|
||||||
|
av_dict_set(&options, "probesize", "32", 0);
|
||||||
|
av_dict_set(&options, "analyzeduration", "0", 0);
|
||||||
|
} else {
|
||||||
av_dict_set(&options, "rtsp_transport", "tcp", 0);
|
av_dict_set(&options, "rtsp_transport", "tcp", 0);
|
||||||
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
int error = avformat_open_input(&format_context, uri.c_str(), nullptr, &options);
|
int error = avformat_open_input(&format_context, uri.c_str(), nullptr, &options);
|
||||||
av_dict_free(&options);
|
av_dict_free(&options);
|
||||||
@@ -278,7 +292,12 @@ int wxMediaCtrl3::PlayRtsp(std::shared_ptr<wxURI> const &url, std::unique_lock<s
|
|||||||
break;
|
break;
|
||||||
if (frame.IsOk())
|
if (frame.IsOk())
|
||||||
m_frame = frame;
|
m_frame = frame;
|
||||||
CallAfter([this] { Refresh(); });
|
if (!m_refresh_pending.exchange(true)) {
|
||||||
|
CallAfter([this] {
|
||||||
|
m_refresh_pending.store(false);
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
av_packet_unref(packet);
|
av_packet_unref(packet);
|
||||||
@@ -301,10 +320,11 @@ void wxMediaCtrl3::PlayThread()
|
|||||||
if (!url->HasScheme())
|
if (!url->HasScheme())
|
||||||
break;
|
break;
|
||||||
const wxString scheme = url->GetScheme();
|
const wxString scheme = url->GetScheme();
|
||||||
const bool generic_rtsp = scheme.CmpNoCase("rtsp") == 0 || scheme.CmpNoCase("rtsps") == 0;
|
const bool generic_ffmpeg = scheme.CmpNoCase("http") == 0 || scheme.CmpNoCase("https") == 0 ||
|
||||||
|
scheme.CmpNoCase("rtsp") == 0 || scheme.CmpNoCase("rtsps") == 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
if (generic_rtsp) {
|
if (generic_ffmpeg) {
|
||||||
error = PlayRtsp(url, lk);
|
error = PlayFfmpeg(url, lk);
|
||||||
} else {
|
} else {
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
Bambu_Tunnel tunnel = nullptr;
|
Bambu_Tunnel tunnel = nullptr;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
|||||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
||||||
|
|
||||||
#define BAMBU_DYNAMIC
|
#define BAMBU_DYNAMIC
|
||||||
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -56,10 +57,10 @@ protected:
|
|||||||
void DoSetSize(int x, int y, int width, int height, int sizeFlags) 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);
|
static void bambu_log(void *ctx, int level, tchar const *msg);
|
||||||
static int rtsp_interrupt_callback(void *opaque);
|
static int ffmpeg_interrupt_callback(void *opaque);
|
||||||
|
|
||||||
void PlayThread();
|
void PlayThread();
|
||||||
int PlayRtsp(std::shared_ptr<wxURI> const &url, std::unique_lock<std::mutex> &lock);
|
int PlayFfmpeg(std::shared_ptr<wxURI> const &url, std::unique_lock<std::mutex> &lock);
|
||||||
|
|
||||||
void NotifyStopped();
|
void NotifyStopped();
|
||||||
|
|
||||||
@@ -83,6 +84,7 @@ private:
|
|||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
std::condition_variable m_cond;
|
std::condition_variable m_cond;
|
||||||
std::thread m_thread;
|
std::thread m_thread;
|
||||||
|
std::atomic_bool m_refresh_pending{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* wxMediaCtrl3_h */
|
#endif /* wxMediaCtrl3_h */
|
||||||
|
|||||||
Reference in New Issue
Block a user