From ff484db284f973c33bacf87c464e185c4f88a2d6 Mon Sep 17 00:00:00 2001 From: niklaspandersson Date: Tue, 3 Sep 2013 10:08:17 +0200 Subject: [PATCH] manually merged 4a2171b from master manually merged 0c06544 from master manually merged 8d99a50 from master --- core/consumer/frame_consumer.cpp | 6 +- core/consumer/output.cpp | 15 ++++- core/consumer/port.cpp | 7 ++- core/consumer/port.h | 1 + core/mixer/audio/audio_mixer.cpp | 20 +++++- core/video_format.cpp | 63 ++++++++++--------- core/video_format.h | 2 +- .../bluefish/consumer/bluefish_consumer.cpp | 9 +++ .../decklink/consumer/decklink_consumer.cpp | 37 ++++++----- .../decklink/producer/decklink_producer.cpp | 2 +- modules/ffmpeg/producer/muxer/frame_muxer.cpp | 10 +-- modules/oal/consumer/oal_consumer.cpp | 4 +- protocol/amcp/AMCPCommandsImpl.cpp | 9 ++- protocol/amcp/AMCPCommandsImpl.h | 27 +++----- protocol/amcp/AMCPProtocolStrategy.cpp | 1 + shell/casparcg_auto_restart.bat | 7 +++ shell/main.cpp | 7 +-- shell/shell.vcxproj | 8 ++- shell/shell.vcxproj.filters | 1 + 19 files changed, 151 insertions(+), 85 deletions(-) create mode 100644 shell/casparcg_auto_restart.bat diff --git a/core/consumer/frame_consumer.cpp b/core/consumer/frame_consumer.cpp index b7da6ce5e..de153d6a5 100644 --- a/core/consumer/frame_consumer.cpp +++ b/core/consumer/frame_consumer.cpp @@ -175,6 +175,7 @@ class cadence_guard : public frame_consumer { spl::shared_ptr consumer_; std::vector audio_cadence_; + video_format_desc format_desc_; boost::circular_buffer sync_buffer_; public: cadence_guard(const spl::shared_ptr& consumer) @@ -186,6 +187,7 @@ public: { audio_cadence_ = format_desc.audio_cadence; sync_buffer_ = boost::circular_buffer(format_desc.audio_cadence.size()); + format_desc_ = format_desc; consumer_->initialize(format_desc, channel_index); } @@ -196,7 +198,7 @@ public: boost::unique_future result = wrap_as_future(true); - if(boost::range::equal(sync_buffer_, audio_cadence_) && audio_cadence_.front() == static_cast(frame.audio_data().size())) + if(boost::range::equal(sync_buffer_, audio_cadence_) && audio_cadence_.front() * format_desc_.audio_channels == static_cast(frame.audio_data().size())) { // Audio sent so far is in sync, now we can send the next chunk. result = consumer_->send(frame); @@ -205,7 +207,7 @@ public: else CASPAR_LOG(trace) << print() << L" Syncing audio."; - sync_buffer_.push_back(static_cast(frame.audio_data().size())); + sync_buffer_.push_back(static_cast(frame.audio_data().size() / format_desc_.audio_channels)); return std::move(result); } diff --git a/core/consumer/output.cpp b/core/consumer/output.cpp index f6aaf6d96..01e4f7b7c 100644 --- a/core/consumer/output.cpp +++ b/core/consumer/output.cpp @@ -180,7 +180,7 @@ public: std::map> send_results; // Start invocations - for (auto it = ports_.begin(); it != ports_.end(); ++it) + for (auto it = ports_.begin(); it != ports_.end();) { auto& port = it->second; auto& frame = frames_.at(port.buffer_depth()-minmax.first); @@ -188,11 +188,22 @@ public: try { send_results.insert(std::make_pair(it->first, port.send(frame))); + ++it; } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); - ports_.erase(it); + try + { + send_results.insert(std::make_pair(it->first, port.send(frame))); + ++it; + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + CASPAR_LOG(error) << "Failed to recover consumer: " << port.print() << L". Removing it."; + it = ports_.erase(it); + } } } diff --git a/core/consumer/port.cpp b/core/consumer/port.cpp index 652690cb4..b85849c9e 100644 --- a/core/consumer/port.cpp +++ b/core/consumer/port.cpp @@ -33,7 +33,11 @@ public: event_subject_ << monitor::event("type") % consumer_->name(); return consumer_->send(std::move(frame)); } - + std::wstring print() const + { + return consumer_->print(); + } + int index() const { return index_; @@ -64,6 +68,7 @@ void port::subscribe(const monitor::observable::observer_ptr& o){impl_->event_su void port::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);} void port::video_format_desc(const struct video_format_desc& format_desc){impl_->video_format_desc(format_desc);} int port::buffer_depth() const{return impl_->buffer_depth();} +std::wstring port::print() const{ return impl_->print();} bool port::has_synchronization_clock() const{return impl_->has_synchronization_clock();} boost::property_tree::wptree port::info() const{return impl_->info();} }} \ No newline at end of file diff --git a/core/consumer/port.h b/core/consumer/port.h index de21c520c..119deb0f7 100644 --- a/core/consumer/port.h +++ b/core/consumer/port.h @@ -37,6 +37,7 @@ public: // Properties void video_format_desc(const struct video_format_desc& format_desc); + std::wstring print() const; int buffer_depth() const; bool has_synchronization_clock() const; boost::property_tree::wptree info() const; diff --git a/core/mixer/audio/audio_mixer.cpp b/core/mixer/audio/audio_mixer.cpp index 8a4bc289f..a97000299 100644 --- a/core/mixer/audio/audio_mixer.cpp +++ b/core/mixer/audio/audio_mixer.cpp @@ -181,9 +181,20 @@ public: audio_streams_ = std::move(next_audio_streams); if(audio_streams_.empty()) - audio_streams_[nullptr].audio_data = audio_buffer_ps(audio_cadence_.front(), 0.0f); + audio_streams_[nullptr].audio_data = audio_buffer_ps(audio_size(audio_cadence_.front()), 0.0f); + + { // sanity check + + auto nb_invalid_streams = boost::count_if(audio_streams_ | boost::adaptors::map_values, [&](const audio_stream& x) + { + return x.audio_data.size() < audio_size(audio_cadence_.front()); + }); + + if(nb_invalid_streams > 0) + CASPAR_LOG(trace) << "[audio_mixer] Incorrect frame audio cadence detected."; + } - std::vector result_ps(audio_cadence_.front(), 0.0f); + std::vector result_ps(audio_size(audio_cadence_.front()), 0.0f); BOOST_FOREACH(auto& stream, audio_streams_ | boost::adaptors::map_values) { if(stream.audio_data.size() < result_ps.size()) @@ -201,6 +212,11 @@ public: return result; } + + size_t audio_size(size_t num_samples) const + { + return num_samples * format_desc_.audio_channels; + } }; audio_mixer::audio_mixer() : impl_(new impl()){} diff --git a/core/video_format.cpp b/core/video_format.cpp index b9f59e928..9306e0185 100644 --- a/core/video_format.cpp +++ b/core/video_format.cpp @@ -29,37 +29,38 @@ namespace caspar { namespace core { const std::vector format_descs = boost::assign::list_of - (video_format_desc(video_format::pal, 720, 576, 1024, 576, field_mode::upper, 25, 1, L"PAL", boost::assign::list_of(3840) )) - (video_format_desc(video_format::ntsc, 720, 486, 720, 540, field_mode::lower, 30000, 1001, L"NTSC", boost::assign::list_of(3204)(3202)(3204)(3202)(3204))) - (video_format_desc(video_format::x576p2500, 720, 576, 720, 576, field_mode::progressive, 25, 1, L"576p2500", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x720p2398, 1280, 720, 1280, 720, field_mode::progressive, 24000, 1001, L"720p2398", boost::assign::list_of(4004) )) - (video_format_desc(video_format::x720p2400, 1280, 720, 1280, 720, field_mode::progressive, 24, 1, L"720p2400", boost::assign::list_of(4000) )) - (video_format_desc(video_format::x720p2500, 1280, 720, 1280, 720, field_mode::progressive, 25, 1, L"720p2500", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x720p5000, 1280, 720, 1280, 720, field_mode::progressive, 50, 1, L"720p5000", boost::assign::list_of(1920) )) - (video_format_desc(video_format::x720p2997, 1280, 720, 1280, 720, field_mode::progressive, 30000, 1001, L"720p2997", boost::assign::list_of(3204)(3202)(3204)(3202)(3204))) - (video_format_desc(video_format::x720p5994, 1280, 720, 1280, 720, field_mode::progressive, 60000, 1001, L"720p5994", boost::assign::list_of(1602)(1601)(1602)(1601)(1602))) - (video_format_desc(video_format::x720p3000, 1280, 720, 1280, 720, field_mode::progressive, 30, 1, L"720p3000", boost::assign::list_of(3200) )) - (video_format_desc(video_format::x720p6000, 1280, 720, 1280, 720, field_mode::progressive, 60, 1, L"720p6000", boost::assign::list_of(1600) )) - (video_format_desc(video_format::x1080p2398, 1920, 1080, 1920, 1080, field_mode::progressive, 24000, 1001, L"1080p2398", boost::assign::list_of(4004) )) - (video_format_desc(video_format::x1080p2400, 1920, 1080, 1920, 1080, field_mode::progressive, 24, 1, L"1080p2400", boost::assign::list_of(4000) )) - (video_format_desc(video_format::x1080i5000, 1920, 1080, 1920, 1080, field_mode::upper, 25, 1, L"1080i5000", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x1080i5994, 1920, 1080, 1920, 1080, field_mode::upper, 30000, 1001, L"1080i5994", boost::assign::list_of(3204)(3202)(3204)(3202)(3204))) - (video_format_desc(video_format::x1080i6000, 1920, 1080, 1920, 1080, field_mode::upper, 30, 1, L"1080i6000", boost::assign::list_of(3200) )) - (video_format_desc(video_format::x1080p2500, 1920, 1080, 1920, 1080, field_mode::progressive, 25, 1, L"1080p2500", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x1080p2997, 1920, 1080, 1920, 1080, field_mode::progressive, 30000, 1001, L"1080p2997", boost::assign::list_of(3204)(3202)(3204)(3202)(3204))) - (video_format_desc(video_format::x1080p3000, 1920, 1080, 1920, 1080, field_mode::progressive, 30, 1, L"1080p3000", boost::assign::list_of(3200) )) - (video_format_desc(video_format::x1080p5000, 1920, 1080, 1920, 1080, field_mode::progressive, 50, 1, L"1080p5000", boost::assign::list_of(1920) )) - (video_format_desc(video_format::x1080p5994, 1920, 1080, 1920, 1080, field_mode::progressive, 60000, 1001, L"1080p5994", boost::assign::list_of(1602)(1601)(1602)(1601)(1602))) - (video_format_desc(video_format::x1080p6000, 1920, 1080, 1920, 1080, field_mode::progressive, 60, 1, L"1080p6000", boost::assign::list_of(1600) )) - (video_format_desc(video_format::x2k2398, 2048, 1556, 2048, 1556, field_mode::progressive, 24000, 1001, L"2k2398", boost::assign::list_of(4004) )) - (video_format_desc(video_format::x2k2400, 2048, 1556, 2048, 1556, field_mode::progressive, 24, 1, L"2k2400", boost::assign::list_of(4000) )) - (video_format_desc(video_format::x2k2500, 2048, 1556, 2048, 1556, field_mode::progressive, 25, 1, L"2k2500", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x4k2398, 3840, 2160, 3840, 2160, field_mode::progressive, 24000, 1001, L"4k2398", boost::assign::list_of(4004) )) - (video_format_desc(video_format::x4k2400, 3840, 2160, 3840, 2160, field_mode::progressive, 24, 1, L"4k2400", boost::assign::list_of(4000) )) - (video_format_desc(video_format::x4k2500, 3840, 2160, 3840, 2160, field_mode::progressive, 25, 1, L"4k2500", boost::assign::list_of(3840) )) - (video_format_desc(video_format::x4k2997, 3840, 2160, 3840, 2160, field_mode::progressive, 30000, 1001, L"4k2398", boost::assign::list_of(3204)(3202)(3204)(3202)(3204))) - (video_format_desc(video_format::x4k3000, 3840, 2160, 3840, 2160, field_mode::progressive, 30, 1, L"4k3000", boost::assign::list_of(3200) )) - (video_format_desc(video_format::invalid, 0, 0, 0, 0, field_mode::progressive, 1, 1, L"invalid", boost::assign::list_of(1) )); + (video_format_desc(video_format::pal, 720, 576, 1024, 576, field_mode::upper, 25, 1, L"PAL", boost::assign::list_of(1920) )) + (video_format_desc(video_format::ntsc, 720, 486, 720, 540, field_mode::lower, 30000, 1001, L"NTSC", boost::assign::list_of(1602) (1601) (1602) (1601) (1602) )) + (video_format_desc(video_format::x576p2500, 720, 576, 720, 576, field_mode::progressive, 25, 1, L"576p2500", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x720p2398, 1280, 720, 1280, 720, field_mode::progressive, 24000, 1001, L"720p2398", boost::assign::list_of(2002) )) + (video_format_desc(video_format::x720p2400, 1280, 720, 1280, 720, field_mode::progressive, 24, 1, L"720p2400", boost::assign::list_of(2000) )) + (video_format_desc(video_format::x720p2500, 1280, 720, 1280, 720, field_mode::progressive, 25, 1, L"720p2500", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x720p5000, 1280, 720, 1280, 720, field_mode::progressive, 50, 1, L"720p5000", boost::assign::list_of(960) )) + (video_format_desc(video_format::x720p2997, 1280, 720, 1280, 720, field_mode::progressive, 30000, 1001, L"720p2997", boost::assign::list_of(1602) (1601) (1602) (1601) (1602) )) + (video_format_desc(video_format::x720p5994, 1280, 720, 1280, 720, field_mode::progressive, 60000, 1001, L"720p5994", boost::assign::list_of(801)(801)(800)(801)(801)(801)(800)(801)(801)(801) )) + (video_format_desc(video_format::x720p3000, 1280, 720, 1280, 720, field_mode::progressive, 30, 1, L"720p3000", boost::assign::list_of(1600) )) + (video_format_desc(video_format::x720p6000, 1280, 720, 1280, 720, field_mode::progressive, 60, 1, L"720p6000", boost::assign::list_of(800) )) + (video_format_desc(video_format::x1080p2398, 1920, 1080, 1920, 1080, field_mode::progressive, 24000, 1001, L"1080p2398", boost::assign::list_of(2002) )) + (video_format_desc(video_format::x1080p2400, 1920, 1080, 1920, 1080, field_mode::progressive, 24, 1, L"1080p2400", boost::assign::list_of(2000) )) + (video_format_desc(video_format::x1080i5000, 1920, 1080, 1920, 1080, field_mode::upper, 25, 1, L"1080i5000", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x1080i5994, 1920, 1080, 1920, 1080, field_mode::upper, 30000, 1001, L"1080i5994", boost::assign::list_of(1602) (1601) (1602) (1601) (1602) )) + (video_format_desc(video_format::x1080i6000, 1920, 1080, 1920, 1080, field_mode::upper, 30, 1, L"1080i6000", boost::assign::list_of(1600) )) + (video_format_desc(video_format::x1080p2500, 1920, 1080, 1920, 1080, field_mode::progressive, 25, 1, L"1080p2500", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x1080p2997, 1920, 1080, 1920, 1080, field_mode::progressive, 30000, 1001, L"1080p2997", boost::assign::list_of(1602) (1601) (1602) (1601) (1602) )) + (video_format_desc(video_format::x1080p3000, 1920, 1080, 1920, 1080, field_mode::progressive, 30, 1, L"1080p3000", boost::assign::list_of(1600) )) + (video_format_desc(video_format::x1080p5000, 1920, 1080, 1920, 1080, field_mode::progressive, 50, 1, L"1080p5000", boost::assign::list_of(960) )) + (video_format_desc(video_format::x1080p5994, 1920, 1080, 1920, 1080, field_mode::progressive, 60000, 1001, L"1080p5994", boost::assign::list_of(801)(801)(800)(801)(801)(801)(800)(801)(801)(801) )) + (video_format_desc(video_format::x1080p6000, 1920, 1080, 1920, 1080, field_mode::progressive, 60, 1, L"1080p6000", boost::assign::list_of(800) )) + (video_format_desc(video_format::x2k2398, 2048, 1556, 2048, 1556, field_mode::progressive, 24000, 1001, L"2k2398", boost::assign::list_of(2002) )) + (video_format_desc(video_format::x2k2400, 2048, 1556, 2048, 1556, field_mode::progressive, 24, 1, L"2k2400", boost::assign::list_of(2000) )) + (video_format_desc(video_format::x2k2500, 2048, 1556, 2048, 1556, field_mode::progressive, 25, 1, L"2k2500", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x4k2398, 3840, 2160, 3840, 2160, field_mode::progressive, 24000, 1001, L"4k2398", boost::assign::list_of(2002) )) + (video_format_desc(video_format::x4k2400, 3840, 2160, 3840, 2160, field_mode::progressive, 24, 1, L"4k2400", boost::assign::list_of(2000) )) + (video_format_desc(video_format::x4k2500, 3840, 2160, 3840, 2160, field_mode::progressive, 25, 1, L"4k2500", boost::assign::list_of(1920) )) + (video_format_desc(video_format::x4k2997, 3840, 2160, 3840, 2160, field_mode::progressive, 30000, 1001, L"4k2398", boost::assign::list_of(1602) (1601) (1602) (1601) (1602) )) + (video_format_desc(video_format::x4k3000, 3840, 2160, 3840, 2160, field_mode::progressive, 30, 1, L"4k3000", boost::assign::list_of(1600) )) + (video_format_desc(video_format::invalid, 0, 0, 0, 0, field_mode::progressive, 1, 1, L"invalid", boost::assign::list_of(1) )); + video_format_desc::video_format_desc(video_format format, int width, diff --git a/core/video_format.h b/core/video_format.h index 0d9eee871..56999b093 100644 --- a/core/video_format.h +++ b/core/video_format.h @@ -100,7 +100,7 @@ struct video_format_desc sealed int audio_sample_rate; int audio_channels; - std::vector audio_cadence; + std::vector audio_cadence; // rotating optimal number of samples per frame video_format_desc(video_format format, int width, diff --git a/modules/bluefish/consumer/bluefish_consumer.cpp b/modules/bluefish/consumer/bluefish_consumer.cpp index cbe48d104..23421ff02 100644 --- a/modules/bluefish/consumer/bluefish_consumer.cpp +++ b/modules/bluefish/consumer/bluefish_consumer.cpp @@ -302,6 +302,10 @@ struct bluefish_consumer_proxy : public core::frame_consumer const int device_index_; const bool embedded_audio_; const bool key_only_; + + std::vector audio_cadence_; + core::video_format_desc format_desc_; + public: bluefish_consumer_proxy(int device_index, bool embedded_audio, bool key_only) @@ -315,12 +319,17 @@ public: void initialize(const core::video_format_desc& format_desc, int channel_index) override { + format_desc_ = format_desc; + audio_cadence_ = format_desc.audio_cadence; + consumer_.reset(); consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, key_only_, channel_index)); } boost::unique_future send(core::const_frame frame) override { + CASPAR_VERIFY(audio_cadence_.front() * format_desc_.audio_channels == static_cast(frame.audio_data().size())); + boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1); return consumer_->send(frame); } diff --git a/modules/decklink/consumer/decklink_consumer.cpp b/modules/decklink/consumer/decklink_consumer.cpp index 769ebc07b..f5e0e69ef 100644 --- a/modules/decklink/consumer/decklink_consumer.cpp +++ b/modules/decklink/consumer/decklink_consumer.cpp @@ -129,12 +129,12 @@ public: // IDecklinkVideoFrame STDMETHOD_(long, GetWidth()) {return static_cast(format_desc_.width);} - STDMETHOD_(long, GetHeight()) {return static_cast(format_desc_.height);} - STDMETHOD_(long, GetRowBytes()) {return static_cast(format_desc_.width*4);} + STDMETHOD_(long, GetHeight()) {return static_cast(format_desc_.height);} + STDMETHOD_(long, GetRowBytes()) {return static_cast(format_desc_.width*4);} STDMETHOD_(BMDPixelFormat, GetPixelFormat()) {return bmdFormat8BitBGRA;} - STDMETHOD_(BMDFrameFlags, GetFlags()) {return bmdFrameFlagDefault;} - - STDMETHOD(GetBytes(void** buffer)) + STDMETHOD_(BMDFrameFlags, GetFlags()) {return bmdFrameFlagDefault;} + + STDMETHOD(GetBytes(void** buffer)) { try { @@ -163,9 +163,9 @@ public: return S_OK; } - - STDMETHOD(GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode)){return S_FALSE;} - STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary)) {return S_FALSE;} + + STDMETHOD(GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode)){return S_FALSE;} + STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary)) {return S_FALSE;} // decklink_frame @@ -229,7 +229,11 @@ public: is_running_ = true; video_frame_buffer_.set_capacity(1); - audio_frame_buffer_.set_capacity(1); + + // Blackmagic calls RenderAudioSamples() 50 times per second + // regardless of video mode so we sometimes need to give them + // samples from 2 frames in order to keep up + audio_frame_buffer_.set_capacity((format_desc.fps > 50.0) ? 2 : 1); graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f)); graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f)); @@ -411,19 +415,24 @@ public: start_playback(); } else - schedule_next_audio(core::audio_buffer(format_desc_.audio_cadence[preroll % format_desc_.audio_cadence.size()], 0)); + { + schedule_next_audio(core::audio_buffer(format_desc_.audio_cadence[preroll % format_desc_.audio_cadence.size()] * format_desc_.audio_channels, 0)); + } } else { auto frame = core::const_frame::empty(); - audio_frame_buffer_.pop(frame); - send_completion_.try_completion(); - schedule_next_audio(frame.audio_data()); + + while(audio_frame_buffer_.try_pop(frame)) + { + send_completion_.try_completion(); + schedule_next_audio(frame.audio_data()); + } } unsigned long buffered; output_->GetBufferedAudioSampleFrameCount(&buffered); - graph_->set_value("buffered-audio", static_cast(buffered)/(format_desc_.audio_cadence[0]*2)); + graph_->set_value("buffered-audio", static_cast(buffered)/(format_desc_.audio_cadence[0]*format_desc_.audio_channels*2)); } catch(...) { diff --git a/modules/decklink/producer/decklink_producer.cpp b/modules/decklink/producer/decklink_producer.cpp index 1a9eac90c..331aa3f81 100644 --- a/modules/decklink/producer/decklink_producer.cpp +++ b/modules/decklink/producer/decklink_producer.cpp @@ -241,7 +241,7 @@ public: // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601) // This cadence fills the audio mixer most optimally. - sync_buffer_.push_back(audio->GetSampleFrameCount()*out_format_desc_.audio_channels); + sync_buffer_.push_back(audio->GetSampleFrameCount()); if(!boost::range::equal(sync_buffer_, audio_cadence_)) { CASPAR_LOG(trace) << print() << L" Syncing audio."; diff --git a/modules/ffmpeg/producer/muxer/frame_muxer.cpp b/modules/ffmpeg/producer/muxer/frame_muxer.cpp index 36b747a0e..99bfb0ddc 100644 --- a/modules/ffmpeg/producer/muxer/frame_muxer.cpp +++ b/modules/ffmpeg/producer/muxer/frame_muxer.cpp @@ -127,7 +127,7 @@ struct frame_muxer::impl : boost::noncopyable if(!audio->data[0]) { - boost::range::push_back(audio_stream_, core::audio_buffer(audio_cadence_.front(), 0)); + boost::range::push_back(audio_stream_, core::audio_buffer(audio_cadence_.front() * format_desc_.audio_channels, 0)); } else { @@ -156,9 +156,9 @@ struct frame_muxer::impl : boost::noncopyable switch(display_mode_) { case display_mode::duplicate: - return audio_stream_.size() >= static_cast(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()]); + return audio_stream_.size() >= static_cast(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()])*format_desc_.audio_channels; default: - return audio_stream_.size() >= static_cast(audio_cadence_.front()); + return audio_stream_.size() >= static_cast(audio_cadence_.front()) * format_desc_.audio_channels; } } @@ -235,11 +235,11 @@ struct frame_muxer::impl : boost::noncopyable core::audio_buffer pop_audio() { - if(audio_stream_.size() < audio_cadence_.front()) + if(audio_stream_.size() < audio_cadence_.front() * format_desc_.audio_channels) CASPAR_THROW_EXCEPTION(out_of_range()); auto begin = audio_stream_.begin(); - auto end = begin + audio_cadence_.front(); + auto end = begin + audio_cadence_.front() * format_desc_.audio_channels; core::audio_buffer samples(begin, end); audio_stream_.erase(begin, end); diff --git a/modules/oal/consumer/oal_consumer.cpp b/modules/oal/consumer/oal_consumer.cpp index 43455fbad..a8d33915f 100644 --- a/modules/oal/consumer/oal_consumer.cpp +++ b/modules/oal/consumer/oal_consumer.cpp @@ -164,7 +164,7 @@ public: for(std::size_t n = 0; n < buffers_.size(); ++n) { - std::vector audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0); + std::vector audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()]*format_desc_.audio_channels, 0); alBufferData(buffers_[n], AL_FORMAT_STEREO16, audio.data(), static_cast(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate); alSourceQueueBuffers(source_, 1, &buffers_[n]); } @@ -191,7 +191,7 @@ public: alSourceUnqueueBuffers(source_, 1, &buffer); if(buffer) { - std::vector audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0); + std::vector audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()] * format_desc_.audio_channels, 0); alBufferData(buffer, AL_FORMAT_STEREO16, audio.data(), static_cast(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate); alSourceQueueBuffers(source_, 1, &buffer); } diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index a0a3e5fac..cc877bada 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -1957,10 +1957,17 @@ bool ThumbnailCommand::DoExecuteGenerateAll() bool KillCommand::DoExecute() { - shutdown_server_now_->set_value(false); //false for not waiting for keypress + shutdown_server_now_->set_value(false); //false for not attempting to restart SetReplyString(TEXT("202 KILL OK\r\n")); return true; } +bool RestartCommand::DoExecute() +{ + shutdown_server_now_->set_value(true); //true for attempting to restart + SetReplyString(TEXT("202 RESTART OK\r\n")); + return true; +} + } //namespace amcp }} //namespace caspar \ No newline at end of file diff --git a/protocol/amcp/AMCPCommandsImpl.h b/protocol/amcp/AMCPCommandsImpl.h index 8fca23c89..4729960f1 100644 --- a/protocol/amcp/AMCPCommandsImpl.h +++ b/protocol/amcp/AMCPCommandsImpl.h @@ -322,23 +322,16 @@ private: boost::promise* shutdown_server_now_; }; -//class KillCommand : public AMCPCommand -//{ -//public: -// KillCommand() {} -// virtual bool DoExecute(); -// virtual AMCPCommandCondition CheckConditions(); -// -// virtual bool NeedChannel() { -// return false; -// } -// virtual AMCPCommandScheduling GetDefaultScheduling() { -// return AddToQueue; -// } -// virtual int GetMinimumParameters() { -// return 0; -// } -//}; +class RestartCommand : public AMCPCommandBase<0> +{ +public: + RestartCommand(IO::ClientInfoPtr client, boost::promise& shutdown_server_now) : AMCPCommandBase(client), shutdown_server_now_(&shutdown_server_now) {} + std::wstring print() const { return L"RestartCommand";} + bool DoExecute(); + +private: + boost::promise* shutdown_server_now_; +}; } //namespace amcp }} //namespace caspar diff --git a/protocol/amcp/AMCPProtocolStrategy.cpp b/protocol/amcp/AMCPProtocolStrategy.cpp index c461fe17b..cc15b5f5c 100644 --- a/protocol/amcp/AMCPProtocolStrategy.cpp +++ b/protocol/amcp/AMCPProtocolStrategy.cpp @@ -359,6 +359,7 @@ private: else if(s == TEXT("LOG")) return std::make_shared(client); else if(s == TEXT("THUMBNAIL")) return std::make_shared(client, thumb_gen_); else if(s == TEXT("KILL")) return std::make_shared(client, shutdown_server_now_); + else if(s == TEXT("RESTART")) return std::make_shared(client, shutdown_server_now_); return nullptr; } diff --git a/shell/casparcg_auto_restart.bat b/shell/casparcg_auto_restart.bat new file mode 100644 index 000000000..9aef2b334 --- /dev/null +++ b/shell/casparcg_auto_restart.bat @@ -0,0 +1,7 @@ +@Echo off +:Start +SET ERRORLEVEL 0 + +casparcg.exe + +if ERRORLEVEL 5 goto :Start diff --git a/shell/main.cpp b/shell/main.cpp index c10c2a6f7..fc86da8c0 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -316,6 +316,7 @@ void on_abort(int) int main(int argc, wchar_t* argv[]) { + int return_code = 0; SetUnhandledExceptionFilter(UserUnhandledExceptionFilter); signal(SIGABRT, on_abort); @@ -391,12 +392,10 @@ int main(int argc, wchar_t* argv[]) boost::property_tree::write_xml(str, env::properties(), w); CASPAR_LOG(info) << L"casparcg.config:\n-----------------------------------------\n" << str.str().c_str() << L"-----------------------------------------"; - auto wait = run(); + return_code = run() ? 5 : 0; Sleep(500); CASPAR_LOG(info) << "Successfully shutdown CasparCG Server."; - - if(wait) system("pause"); } catch(boost::property_tree::file_parser_error&) { @@ -413,5 +412,5 @@ int main(int argc, wchar_t* argv[]) Sleep(4000); } - return 0; + return return_code; } \ No newline at end of file diff --git a/shell/shell.vcxproj b/shell/shell.vcxproj index 44be3361b..78088c4d1 100644 --- a/shell/shell.vcxproj +++ b/shell/shell.vcxproj @@ -70,6 +70,7 @@ Designer + @@ -176,7 +177,9 @@ copy "$(SolutionDir)dependencies64\tbb\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\glew\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\freeimage\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\openal\bin\*.dll" "$(OutDir)" -copy "$(ProjectDir)casparcg.config" "$(OutDir)" +copy "$(ProjectDir)casparcg.config" "$(OutDir)" +copy "$(ProjectDir)casparcg_auto_restart.bat" "$(OutDir)" + @@ -223,7 +226,8 @@ copy "$(SolutionDir)dependencies64\tbb\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\glew\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\freeimage\bin\*.dll" "$(OutDir)" copy "$(SolutionDir)dependencies64\openal\bin\*.dll" "$(OutDir)" -copy "$(ProjectDir)casparcg.config" "$(OutDir)" +copy "$(ProjectDir)casparcg.config" "$(OutDir)" +copy "$(ProjectDir)casparcg_auto_restart.bat" "$(OutDir)" diff --git a/shell/shell.vcxproj.filters b/shell/shell.vcxproj.filters index 30fdc61e0..06b5d5743 100644 --- a/shell/shell.vcxproj.filters +++ b/shell/shell.vcxproj.filters @@ -14,6 +14,7 @@ + -- 2.39.2