\r
std::vector<const producer_factory_t> g_factories;\r
std::vector<const producer_factory_t> g_thumbnail_factories;\r
+\r
+tbb::atomic<bool>& destroy_producers_in_separate_thread()\r
+{\r
+ static tbb::atomic<bool> state;\r
+\r
+ return state;\r
+}\r
+\r
+void destroy_producers_synchronously()\r
+{\r
+ destroy_producers_in_separate_thread() = false;\r
+}\r
\r
class destroy_producer_proxy : public frame_producer\r
{ \r
destroy_producer_proxy(safe_ptr<frame_producer>&& producer) \r
: producer_(new std::shared_ptr<frame_producer>(std::move(producer)))\r
{\r
+ destroy_producers_in_separate_thread() = true;\r
}\r
\r
~destroy_producer_proxy()\r
- { \r
+ {\r
static auto destroyers = std::make_shared<tbb::concurrent_bounded_queue<std::shared_ptr<executor>>>();\r
static tbb::atomic<int> destroyer_count;\r
\r
+ if (!destroy_producers_in_separate_thread())\r
+ {\r
+ try\r
+ {\r
+ producer_.reset();\r
+\r
+ std::shared_ptr<executor> destroyer;\r
+\r
+ // Destruct any executors, causing them to execute pending tasks\r
+ while (destroyers->try_pop(destroyer))\r
+ --destroyer_count;\r
+ }\r
+ catch (...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
try\r
{\r
std::shared_ptr<executor> destroyer;\r
safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer> producer);\r
safe_ptr<core::frame_producer> create_producer_print_proxy(safe_ptr<core::frame_producer> producer);\r
safe_ptr<core::frame_producer> create_thumbnail_producer(const safe_ptr<frame_factory>& factory, const std::wstring& media_file);\r
+void destroy_producers_synchronously();\r
\r
}}\r
\r
~implementation()\r
{ \r
- ffmpeg::uninit();\r
-\r
thumbnail_generator_.reset();\r
primary_amcp_server_.reset();\r
async_servers_.clear();\r
+ destroy_producers_synchronously();\r
channels_.clear();\r
+\r
+ ffmpeg::uninit();\r
}\r
\r
void setup_audio(const boost::property_tree::wptree& pt)\r