]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 8 May 2011 00:12:38 +0000 (00:12 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 8 May 2011 00:12:38 +0000 (00:12 +0000)
 decklink_consumer: Some minor refactoring. Added some more graph warning tags.
 flash_producer: Added tick-time graph.
 main: Waits for pressed key before shutting down.

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@694 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

common/utility/timer.h
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/util/util.h
modules/flash/producer/flash_producer.cpp
shell/caspar.config
shell/main.cpp

index 16108268524d9015a771aeabbebb89247c38eec9..fe1ca592c9db2217d6a632e045ab7f89b6ce880f 100644 (file)
@@ -41,14 +41,14 @@ public:
 \r
                if (time_.QuadPart != 0)\r
                {\r
-                       int ticks_to_wait = static_cast<int>(static_cast<double>(freq_.QuadPart) * interval);\r
-                       int done = 0;\r
+                       __int64 ticks_to_wait = static_cast<int>(static_cast<double>(freq_.QuadPart) * interval);\r
+                       __int64 done = 0;\r
                        do\r
                        {\r
                                QueryPerformanceCounter(&t);\r
                                \r
-                               int ticks_passed = static_cast<int>(static_cast<__int64>(t.QuadPart) - static_cast<__int64>(time_.QuadPart));\r
-                               int ticks_left = ticks_to_wait - ticks_passed;\r
+                               __int64 ticks_passed = static_cast<__int64>(t.QuadPart) - static_cast<__int64>(time_.QuadPart);\r
+                               __int64 ticks_left = ticks_to_wait - ticks_passed;\r
 \r
                                if (t.QuadPart < time_.QuadPart)    // time wrap\r
                                        done = 1;\r
@@ -63,7 +63,7 @@ public:
                                        // otherwise, do a few Sleep(0)'s, which just give up the timeslice,\r
                                        //   but don't really save cpu or battery, but do pass a tiny\r
                                        //   amount of time.\r
-                                       if (ticks_left > static_cast<int>((freq_.QuadPart*2)/1000))\r
+                                       if (ticks_left > static_cast<__int64>((freq_.QuadPart*2)/1000))\r
                                                Sleep(1);\r
                                        else                        \r
                                                for (int i = 0; i < 10; ++i) \r
index 30e1e47b287f66b081af92c87055f141c0294a6c..8cdffcbb28b47308bdedb5be948161bddda31b75 100644 (file)
@@ -94,76 +94,69 @@ struct decklink_output : public IDeckLinkVideoOutputCallback, public IDeckLinkAu
                ~co_init(){CoUninitialize();}\r
        } co_;\r
        \r
-       std::exception_ptr exception_;\r
        const configuration config_;\r
 \r
-       std::wstring model_name_;\r
-       tbb::atomic<bool> is_running_;\r
-\r
-       std::shared_ptr<diagnostics::graph> graph_;\r
-       boost::timer perf_timer_;\r
-\r
-       std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, BUFFER_SIZE+1> reserved_frames_;\r
-       boost::circular_buffer<std::vector<short>> audio_container_;\r
-       \r
        CComPtr<IDeckLink>                                      decklink_;\r
        CComQIPtr<IDeckLinkOutput>                      output_;\r
        CComQIPtr<IDeckLinkConfiguration>       configuration_;\r
        CComQIPtr<IDeckLinkKeyer>                       keyer_;\r
 \r
+       std::exception_ptr exception_;\r
+\r
+       tbb::atomic<bool> is_running_;\r
+               \r
+       const std::wstring model_name_;\r
        const core::video_format_desc format_desc_;\r
 \r
        BMDTimeScale frame_time_scale_;\r
        BMDTimeValue frame_duration_;\r
        unsigned long frames_scheduled_;\r
        unsigned long audio_scheduled_;\r
-       \r
+               \r
+       std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, BUFFER_SIZE+1> reserved_frames_;\r
+       boost::circular_buffer<std::vector<short>> audio_container_;\r
+\r
        tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> video_frame_buffer_;\r
        tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> audio_frame_buffer_;\r
+       \r
+       std::shared_ptr<diagnostics::graph> graph_;\r
+       boost::timer tick_timer_;\r
 \r
 public:\r
        decklink_output(const configuration& config, const core::video_format_desc& format_desc) \r
-               : model_name_(L"DECKLINK")\r
-               , config_(config)\r
+               : config_(config)\r
+               , decklink_(get_device(config.device_index))\r
+               , output_(decklink_)\r
+               , configuration_(decklink_)\r
+               , keyer_(decklink_)\r
+               , model_name_(get_model_name(decklink_))\r
+               , format_desc_(format_desc)\r
                , audio_container_(5)\r
                , frames_scheduled_(0)\r
                , audio_scheduled_(0)\r
-               , format_desc_(format_desc)\r
        {\r
                is_running_ = true;\r
-               CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
-               if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " No Decklink drivers installed."));\r
-               \r
-               size_t n = 0;\r
-               while(n < config_.device_index && pDecklinkIterator->Next(&decklink_) == S_OK){++n;}    \r
-\r
-               if(n != config_.device_index || !decklink_)\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Decklink card not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(config_.device_index)));\r
-               \r
-               BSTR pModelName;\r
-               decklink_->GetModelName(&pModelName);\r
-               model_name_ = std::wstring(pModelName);\r
-                               \r
+                                               \r
                graph_ = diagnostics::create_graph(narrow(print()));\r
                graph_->add_guide("tick-time", 0.5);\r
                graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
+               graph_->set_color("flushed-frame", diagnostics::color(0.3f, 0.3f, 0.6f));\r
                \r
-               output_ = decklink_;\r
-               configuration_ = decklink_;\r
-               keyer_ = decklink_;\r
-\r
-               auto display_mode = get_display_mode(output_.p, format_desc_.format);\r
+               auto display_mode = get_display_mode(output_, format_desc_.format);\r
                if(display_mode == nullptr) \r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Card does not support requested videoformat."));\r
                \r
                display_mode->GetFrameRate(&frame_duration_, &frame_time_scale_);\r
 \r
                BMDDisplayModeSupport displayModeSupport;\r
-               if(FAILED(output_->DoesSupportVideoMode(display_mode->GetDisplayMode(), bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, &displayModeSupport, nullptr)))\r
+               if(FAILED(output_->DoesSupportVideoMode(display_mode->GetDisplayMode(), bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, &displayModeSupport, nullptr)) || displayModeSupport == bmdDisplayModeNotSupported)\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Card does not support requested videoformat."));\r
-               \r
-               if(config_.embedded_audio)\r
+               else if(displayModeSupport == bmdDisplayModeSupportedWithConversion)\r
+                       CASPAR_LOG(warning) << print() << " Display mode is supported with conversion.";\r
+\r
+               if(config.embedded_audio)\r
                {\r
                        if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2, bmdAudioOutputStreamTimestamped)))\r
                                BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not enable audio output."));\r
@@ -174,12 +167,12 @@ public:
                        CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";\r
                }\r
 \r
-               if(config_.latency == normal_latency)\r
+               if(config.latency == normal_latency)\r
                {\r
                        configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, false);\r
                        CASPAR_LOG(info) << print() << L" Enabled normal-latency mode";\r
                }\r
-               else if(config_.latency == low_latency)\r
+               else if(config.latency == low_latency)\r
                {                       \r
                        configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, true);\r
                        CASPAR_LOG(info) << print() << L" Enabled low-latency mode";\r
@@ -187,7 +180,7 @@ public:
                else\r
                        CASPAR_LOG(info) << print() << L" Uses driver latency settings.";       \r
                \r
-               if(config_.keyer == internal_key) \r
+               if(config.keyer == internal_key) \r
                {\r
                        if(FAILED(keyer_->Enable(FALSE)))                       \r
                                CASPAR_LOG(error) << print() << L" Failed to enable internal keyer.";                   \r
@@ -214,12 +207,12 @@ public:
                if(FAILED(output_->SetScheduledFrameCompletionCallback(this)))\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to set playback completion callback."));\r
                                        \r
-               for(size_t n = 0; n < reserved_frames_.size(); ++n)\r
+               BOOST_FOREACH(auto& frame, reserved_frames_)\r
                {\r
-                       if(FAILED(output_->CreateVideoFrame(format_desc_.width, format_desc_.height, format_desc_.size/format_desc_.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &reserved_frames_[n].second)))\r
+                       if(FAILED(output_->CreateVideoFrame(format_desc_.width, format_desc_.height, format_desc_.size/format_desc_.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &frame.second)))\r
                                BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to create frame."));\r
 \r
-                       if(FAILED(reserved_frames_[n].second->GetBytes(&reserved_frames_[n].first)))\r
+                       if(FAILED(frame.second->GetBytes(&frame.first)))\r
                                BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to get frame bytes."));\r
                }\r
 \r
@@ -231,7 +224,7 @@ public:
                video_frame_buffer_.set_capacity(2);\r
                audio_frame_buffer_.set_capacity(2);\r
                \r
-               if(config_.embedded_audio)\r
+               if(config.embedded_audio)\r
                        output_->BeginAudioPreroll();\r
                else\r
                {\r
@@ -245,6 +238,8 @@ public:
        ~decklink_output()\r
        {               \r
                is_running_ = false;\r
+               video_frame_buffer_.clear();\r
+               audio_frame_buffer_.clear();\r
                video_frame_buffer_.try_push(core::read_frame::empty());\r
                audio_frame_buffer_.try_push(core::read_frame::empty());\r
 \r
@@ -255,17 +250,23 @@ public:
                                output_->DisableAudioOutput();\r
                        output_->DisableVideoOutput();\r
                }\r
-               CASPAR_LOG(info) << print() << L" Shutting down.";      \r
        }\r
                        \r
        virtual HRESULT STDMETHODCALLTYPE       QueryInterface (REFIID, LPVOID*)        {return E_NOINTERFACE;}\r
        virtual ULONG STDMETHODCALLTYPE         AddRef ()                                                       {return 1;}\r
        virtual ULONG STDMETHODCALLTYPE         Release ()                                                      {return 1;}\r
        \r
-       virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted (IDeckLinkVideoFrame* /*completedFrame*/, BMDOutputFrameCompletionResult /*result*/)\r
+       virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame* /*completedFrame*/, BMDOutputFrameCompletionResult result)\r
        {\r
                if(!is_running_)\r
-                       return S_OK;\r
+                       return E_FAIL;\r
+\r
+               if(result == bmdOutputFrameDisplayedLate)\r
+                       graph_->add_tag("late-frame");\r
+               else if(result == bmdOutputFrameDropped)\r
+                       graph_->add_tag("dropped-frame");\r
+               else if(result == bmdOutputFrameFlushed)\r
+                       graph_->add_tag("flushed-frame");\r
 \r
                std::shared_ptr<const core::read_frame> frame;  \r
                video_frame_buffer_.pop(frame);         \r
@@ -277,14 +278,14 @@ public:
        virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped (void)\r
        {\r
                is_running_ = false;\r
-               CASPAR_LOG(info) << print() << L"Scheduled playback has stopped.";\r
+               CASPAR_LOG(info) << print() << L" Scheduled playback has stopped.";\r
                return S_OK;\r
        }\r
                \r
-       virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples (BOOL preroll)\r
+       virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples(BOOL preroll)\r
        {\r
                if(!is_running_)\r
-                       return S_OK;\r
+                       return E_FAIL;\r
                \r
                try\r
                {\r
@@ -312,13 +313,12 @@ public:
        {\r
                static std::vector<short> silence(48000, 0);\r
 \r
-               int audio_samples = static_cast<size_t>(48000.0 / format_desc_.fps);\r
-\r
-               auto frame_audio_data = frame->audio_data().empty() ? silence.data() : const_cast<short*>(frame->audio_data().begin());\r
+               int audio_samples = static_cast<size_t>(48000.0 / format_desc_.fps)*2; // Audio samples per channel\r
 \r
-               audio_container_.push_back(std::vector<short>(frame_audio_data, frame_audio_data+audio_samples*2));\r
+               const short* frame_audio_data = frame->audio_data().size() == audio_samples ? frame->audio_data().begin() : silence.data();\r
+               audio_container_.push_back(std::vector<short>(frame_audio_data, frame_audio_data+audio_samples));\r
 \r
-               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), audio_samples, (audio_scheduled_++) * audio_samples, 48000, nullptr)))\r
+               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), audio_samples/2, (audio_scheduled_++) * audio_samples/2, 48000, nullptr)))\r
                        CASPAR_LOG(error) << print() << L" Failed to schedule audio.";\r
        }\r
                        \r
@@ -333,8 +333,8 @@ public:
                        CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
 \r
                std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
-               graph_->update_value("tick-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval)*0.5f);\r
-               perf_timer_.restart();\r
+               graph_->update_value("tick-time", static_cast<float>(tick_timer_.elapsed()/format_desc_.interval)*0.5f);\r
+               tick_timer_.restart();\r
        }\r
 \r
        void send(const safe_ptr<const core::read_frame>& frame)\r
@@ -366,7 +366,7 @@ public:
 \r
        decklink_consumer(const configuration& config)\r
                : config_(config)\r
-               , executor_(L"DECKLINK[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]", true){}\r
+               , executor_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]", true){}\r
 \r
        ~decklink_consumer()\r
        {\r
index f7f35be7a0a1ce6f60b28c32829e63ebf6d85148..d005711a4e05641cd1e9d54ab0008687f0637891 100644 (file)
 */\r
 #pragma once\r
 \r
+#include <common/exception/exceptions.h>\r
 #include <core/video_format.h>\r
 \r
 #include "../interop/DeckLinkAPI_h.h"\r
 \r
+#include <atlbase.h>\r
+\r
 namespace caspar { \r
        \r
 static BMDDisplayMode GetDecklinkVideoFormat(core::video_format::type fmt) \r
@@ -48,9 +51,10 @@ static BMDDisplayMode GetDecklinkVideoFormat(core::video_format::type fmt)
        }\r
 }\r
        \r
-static IDeckLinkDisplayMode* get_display_mode(IDeckLinkOutput* output, BMDDisplayMode format)\r
+template<typename T>\r
+static IDeckLinkDisplayMode* get_display_mode(const T& output, BMDDisplayMode format)\r
 {\r
-       IDeckLinkDisplayModeIterator*           iterator;\r
+       CComPtr<IDeckLinkDisplayModeIterator> iterator;\r
        IDeckLinkDisplayMode*                           mode;\r
        \r
        if(FAILED(output->GetDisplayModeIterator(&iterator)))\r
@@ -61,27 +65,52 @@ static IDeckLinkDisplayMode* get_display_mode(IDeckLinkOutput* output, BMDDispla
                if(mode->GetDisplayMode() == format)\r
                        return mode;\r
        }\r
-       iterator->Release();\r
+\r
        return nullptr;\r
 }\r
 \r
-static IDeckLinkDisplayMode* get_display_mode(IDeckLinkOutput* output, core::video_format::type fmt)\r
+template<typename T>\r
+static IDeckLinkDisplayMode* get_display_mode(const T& output, core::video_format::type fmt)\r
 {\r
        return get_display_mode(output, GetDecklinkVideoFormat(fmt));\r
 }\r
 \r
 template<typename T>\r
-static std::wstring get_version(T& deckLinkIterator)\r
+static std::wstring get_version(T& iterator)\r
 {\r
-       IDeckLinkAPIInformation* deckLinkAPIInformation;\r
-       if (FAILED(deckLinkIterator->QueryInterface(IID_IDeckLinkAPIInformation, (void**)&deckLinkAPIInformation)))\r
+       CComQIPtr<IDeckLinkAPIInformation> info = iterator;\r
+       if (!info)\r
                return L"Unknown";\r
        \r
        BSTR ver;               \r
-       deckLinkAPIInformation->GetString(BMDDeckLinkAPIVersion, &ver);\r
-       deckLinkAPIInformation->Release();      \r
+       info->GetString(BMDDeckLinkAPIVersion, &ver);\r
                \r
        return ver;                                     \r
 }\r
 \r
+static CComPtr<IDeckLink> get_device(size_t device_index)\r
+{\r
+       CComPtr<IDeckLink> decklink;\r
+\r
+       CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
+       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
+               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("No Decklink drivers installed."));\r
+               \r
+       size_t n = 0;\r
+       while(n < device_index && pDecklinkIterator->Next(&decklink) == S_OK){++n;}     \r
+\r
+       if(n != device_index || !decklink)\r
+               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink card not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index)));\r
+               \r
+       return decklink;\r
+}\r
+\r
+template <typename T>\r
+static std::wstring get_model_name(const T& device)\r
+{      \r
+       BSTR pModelName;\r
+       device->GetModelName(&pModelName);\r
+       return std::wstring(pModelName);\r
+}\r
+\r
 }
\ No newline at end of file
index e141f2a0b16426a64fe3b79b2bd33baa9bbf77a8..65b2e4321fc77eff21363f5918525e4c4cbfc1a6 100644 (file)
@@ -70,7 +70,8 @@ class flash_renderer
        safe_ptr<core::basic_frame> head_;\r
        \r
        safe_ptr<diagnostics::graph> graph_;\r
-       boost::timer perf_timer_;\r
+       boost::timer frame_timer_;\r
+       boost::timer tick_timer_;\r
 \r
        high_prec_timer timer_;\r
        \r
@@ -87,6 +88,8 @@ public:
        {\r
                graph_->add_guide("frame-time", 0.5f);\r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));  \r
+               graph_->add_guide("tick-time", 0.5);\r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                graph_->set_color("param", diagnostics::color(1.0f, 0.5f, 0.0f));       \r
                graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));                   \r
                \r
@@ -149,17 +152,20 @@ public:
        \r
        safe_ptr<core::basic_frame> render_frame(bool has_underflow)\r
        {\r
-               if(ax_->IsEmpty())\r
-                       return core::basic_frame::empty();\r
+               float frame_time = 1.0f/ax_->GetFPS();\r
+\r
+               graph_->update_value("tick-time", static_cast<float>(tick_timer_.elapsed()/frame_time)*0.5f);\r
+               tick_timer_.restart();\r
 \r
-               double frame_time = 1.0/ax_->GetFPS();\r
+               if(ax_->IsEmpty())\r
+                       return core::basic_frame::empty();              \r
                \r
                if(!has_underflow)                      \r
                        timer_.tick(frame_time);        \r
                else\r
                        graph_->add_tag("underflow");\r
                        \r
-               perf_timer_.restart();\r
+               frame_timer_.restart();\r
 \r
                ax_->Tick();\r
                if(ax_->InvalidRect())\r
@@ -171,9 +177,8 @@ public:
                        fast_memcpy(frame->image_data().begin(), bmp_data_, format_desc_.size);\r
                        head_ = frame;\r
                }               \r
-               \r
-               \r
-               graph_->update_value("frame-time", static_cast<float>(perf_timer_.elapsed()/frame_time)*0.5f);\r
+                               \r
+               graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()/frame_time)*0.5f);\r
                return head_;\r
        }\r
 \r
index 90a55a107a2ac042bf2d932b35ed4003719fe6ea..65e587a6d619bfcd4efa94a14dcb96fe589c457c 100644 (file)
@@ -12,7 +12,7 @@
   </diagnostics>\r
   <channels>\r
     <channel>\r
-      <videomode>1080i5000</videomode>\r
+      <videomode>PAL</videomode>\r
       <consumers>\r
         <decklink>\r
           <device>1</device>\r
index 1dbcb21fd37bfdfd426f78a810badc8dc90a4172..507a7018605bc2ae82447810c1fede581a6d5111 100644 (file)
@@ -227,11 +227,11 @@ int main(int argc, wchar_t* argv[])
        {\r
                CASPAR_LOG(fatal) << "UNHANDLED EXCEPTION in main thread.";\r
                CASPAR_LOG_CURRENT_EXCEPTION();\r
-               std::wcout << L"Press Any Key To Exit.\n";\r
-               _getwch();\r
        }       \r
        \r
        CASPAR_LOG(info) << "Successfully shutdown CasparCG Server.";\r
-       \r
+       Sleep(100); // CAPSAR_LOG is asynchronous. Try to get text in correct order.\r
+       std::wcout << L"Press Any Key To Exit.\n";\r
+       _getwch();\r
        return 0;\r
 }
\ No newline at end of file