#include "../../server.h"\r
#include "../../../common/concurrency/executor.h"\r
#include "../../../common/concurrency/concurrent_queue.h"\r
-#include "../../../common/utility/scope_exit.h"\r
\r
#include "../../processor/draw_frame.h"\r
#include "../../processor/composite_frame.h"\r
\r
-#include <boost/assign.hpp>\r
#include <boost/filesystem.hpp>\r
#include <boost/thread.hpp>\r
\r
CComModule _AtlModule;\r
extern __declspec(selectany) CAtlModule* _pAtlModule = &_AtlModule;\r
\r
-struct flash_producer::implementation\r
-{ \r
- implementation(flash_producer* self, const std::wstring& filename) \r
- : flashax_container_(nullptr), filename_(filename), self_(self), executor_([=]{run();}), invalid_count_(0), last_frame_(draw_frame::empty())\r
- { \r
- if(!boost::filesystem::exists(filename))\r
- BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
-\r
- frame_buffer_.set_capacity(3);\r
- }\r
+class flash_renderer\r
+{\r
+public:\r
+ flash_renderer(const safe_ptr<frame_processor_device>& frame_processor, const std::wstring& filename) \r
+ : last_frame_(draw_frame::empty()), current_frame_(draw_frame::empty()), frame_processor_(frame_processor), filename_(filename),\r
+ format_desc_(frame_processor->get_video_format_desc()), bmp_frame_(std::make_shared<bitmap>(format_desc_.width, format_desc_.height))\r
\r
- ~implementation() \r
{\r
- stop();\r
- }\r
+ CASPAR_LOG(info) << print() << L" Started";\r
\r
- void start()\r
- { \r
- try\r
- {\r
- safe_ptr<draw_frame> frame = draw_frame::eof();\r
- while(frame_buffer_.try_pop(frame)){}\r
+ ::OleInitialize(nullptr);\r
\r
- is_empty_ = true;\r
- executor_.stop(); // Restart if running\r
- executor_.start();\r
- executor_.invoke([=]()\r
- {\r
- if(FAILED(CComObject<FlashAxContainer>::CreateInstance(&flashax_container_)) || \r
- flashax_container_ == nullptr)\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to create FlashAxContainer"));\r
+ CComObject<FlashAxContainer>* object; \r
+ if(FAILED(CComObject<FlashAxContainer>::CreateInstance(&object)))\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to create FlashAxContainer"));\r
\r
- flashax_container_->pflash_producer_ = self_;\r
- CComPtr<IShockwaveFlash> spFlash;\r
-\r
- if(FAILED(flashax_container_->CreateAxControl()))\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to Create FlashAxControl"));\r
-\r
- if(FAILED(flashax_container_->QueryControl(&spFlash)))\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to Query FlashAxControl"));\r
- \r
- if(FAILED(spFlash->put_Playing(true)) )\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to start playing Flash"));\r
-\r
- if(FAILED(spFlash->put_Movie(CComBSTR(filename_.c_str()))))\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to Load Template Host"));\r
- \r
- //Exact fit. Scale without respect to the aspect ratio.\r
- if(FAILED(spFlash->put_ScaleMode(2))) \r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to Set Scale Mode"));\r
+ object->AddRef();\r
+ ax_.Attach(object);\r
+ \r
+ if(FAILED(ax_->CreateAxControl()))\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Create FlashAxControl"));\r
+ \r
+ CComPtr<IShockwaveFlash> spFlash;\r
+ if(FAILED(ax_->QueryControl(&spFlash)))\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Query FlashAxControl"));\r
\r
- // stop if failed\r
- if(FAILED(flashax_container_->SetFormat(frame_processor_->get_video_format_desc()))) \r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to Set Format"));\r
-\r
- current_frame_ = nullptr; // Force re-render of current frame \r
- last_frame_ = draw_frame::empty();\r
- });\r
- }\r
- catch(...)\r
- {\r
- stop();\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- throw;\r
- }\r
+ if(FAILED(spFlash->put_Playing(true)) )\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to start playing Flash"));\r
+\r
+ if(FAILED(spFlash->put_Movie(CComBSTR(filename.c_str()))))\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Load Template Host"));\r
+ \r
+ if(FAILED(spFlash->put_ScaleMode(2))) //Exact fit. Scale without respect to the aspect ratio.\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Set Scale Mode"));\r
+ \r
+ if(FAILED(ax_->SetFormat(frame_processor_->get_video_format_desc()))) // stop if failed\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Set Format"));\r
}\r
\r
- void stop()\r
+ ~flash_renderer()\r
{\r
- is_empty_ = true;\r
- if(executor_.is_running())\r
- {\r
- safe_ptr<draw_frame> frame = draw_frame::eof();\r
- while(frame_buffer_.try_pop(frame)){}\r
- executor_.stop();\r
- }\r
+ ax_->DestroyAxControl();\r
+ ax_.Release();\r
+ ::OleUninitialize();\r
+ CASPAR_LOG(info) << print() << L" Ended";\r
}\r
\r
void param(const std::wstring& param) \r
- { \r
- if(!executor_.is_running())\r
- start();\r
-\r
- executor_.invoke([&]()\r
- { \r
- for(size_t retries = 0; !flashax_container_->CallFunction(param); ++retries)\r
- {\r
- CASPAR_LOG(debug) << "Retrying. Count: " << retries;\r
- if(retries > 3)\r
- BOOST_THROW_EXCEPTION(operation_failed() << arg_name_info("param") << arg_value_info(narrow(param)));\r
- }\r
- is_empty_ = false; \r
- });\r
- }\r
- \r
- void run()\r
- {\r
- win32_exception::install_handler();\r
- CASPAR_LOG(info) << L"started flash_producer Thread";\r
-\r
- try\r
- {\r
- ::OleInitialize(nullptr);\r
- CASPAR_SCOPE_EXIT(::OleUninitialize);\r
-\r
- CASPAR_SCOPE_EXIT([=]\r
- {\r
- if(flashax_container_)\r
- {\r
- flashax_container_->DestroyAxControl();\r
- flashax_container_->Release();\r
- flashax_container_ = nullptr;\r
- }\r
- });\r
- \r
- while(executor_.is_running())\r
- { \r
- if(!is_empty_)\r
- {\r
- render(); \r
- while(executor_.try_execute()){}\r
- }\r
- else \r
- executor_.execute(); \r
- }\r
- }\r
- catch(...)\r
+ { \r
+ for(size_t retries = 0; !ax_->CallFunction(param); ++retries)\r
{\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(debug) << print() << L" Retrying. Count: " << retries;\r
+ if(retries > 3)\r
+ BOOST_THROW_EXCEPTION(operation_failed() << arg_name_info("param") << arg_value_info(narrow(param)) << msg_info(narrow(print())));\r
}\r
- \r
- frame_buffer_.try_push(draw_frame::eof()); // EOF\r
- CASPAR_LOG(info) << L"Ended flash_producer Thread";\r
}\r
-\r
+ \r
void render()\r
- { \r
- if(!is_empty_ || current_frame_ == nullptr)\r
+ { \r
+ while(frame_buffer_.size() < 3)\r
{\r
- bool is_progressive = format_desc_.mode == video_mode::progressive || (flashax_container_->GetFPS() - format_desc_.fps/2 == 0);\r
+ bool is_progressive = format_desc_.mode == video_mode::progressive || (ax_->GetFPS() - format_desc_.fps/2 == 0);\r
\r
safe_ptr<draw_frame> frame = render_frame();\r
if(!is_progressive)\r
frame = composite_frame::interlace(frame, render_frame(), format_desc_.mode);\r
\r
- frame_buffer_.push(std::move(frame));\r
- is_empty_ = flashax_container_->IsEmpty();\r
+ frame_buffer_.try_push(std::move(frame));\r
}\r
}\r
\r
safe_ptr<draw_frame> render_frame()\r
{\r
- if(!flashax_container_->IsReadyToRender())\r
- return draw_frame::empty();\r
-\r
- flashax_container_->Tick();\r
- invalid_count_ = !flashax_container_->InvalidRectangle() ? std::min(2, invalid_count_+1) : 0;\r
- if(current_frame_ == nullptr || invalid_count_ < 2)\r
+ ax_->Tick();\r
+ \r
+ if(ax_->IsReadyToRender() && ax_->InvalidRectangle())\r
{\r
std::fill_n(bmp_frame_->data(), bmp_frame_->size(), 0); \r
- flashax_container_->DrawControl(bmp_frame_->hdc());\r
- current_frame_ = bmp_frame_;\r
+ ax_->DrawControl(bmp_frame_->hdc());\r
+ \r
+ auto frame = frame_processor_->create_frame();\r
+ std::copy(bmp_frame_->data(), bmp_frame_->data() + bmp_frame_->size(), frame->pixel_data().begin());\r
+ current_frame_ = frame;\r
}\r
-\r
- auto frame = frame_processor_->create_frame(format_desc_.width, format_desc_.height);\r
- std::copy(current_frame_->data(), current_frame_->data() + current_frame_->size(), frame->pixel_data().begin());\r
- return frame;\r
+ return current_frame_;\r
}\r
-\r
+ \r
safe_ptr<draw_frame> receive()\r
{\r
- return frame_buffer_.try_pop(last_frame_) || !is_empty_ ? last_frame_ : draw_frame::empty();\r
+ frame_buffer_.try_pop(last_frame_);\r
+ return last_frame_;\r
}\r
\r
- void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
- {\r
- frame_processor_ = frame_processor;\r
- format_desc_ = frame_processor_->get_video_format_desc();\r
- bmp_frame_ = std::make_shared<bitmap>(format_desc_.width, format_desc_.height);\r
- start();\r
+ std::wstring print() const{ return L"flash[" + filename_ + L"]"; }\r
+ std::string bprint() const{ return narrow(L"flash[" + filename_ + L"]"); }\r
+\r
+private:\r
+ const std::wstring filename_;\r
+ const safe_ptr<frame_processor_device> frame_processor_;\r
+ const video_format_desc format_desc_;\r
+ const safe_ptr<bitmap> bmp_frame_; \r
+\r
+ CComPtr<FlashAxContainer> ax_;\r
+ concurrent_bounded_queue_r<safe_ptr<draw_frame>> frame_buffer_; \r
+ safe_ptr<draw_frame> last_frame_;\r
+ safe_ptr<draw_frame> current_frame_;\r
+};\r
+\r
+struct flash_producer::implementation\r
+{ \r
+ implementation(const std::wstring& filename) : filename_(filename)\r
+ { \r
+ if(!boost::filesystem::exists(filename))\r
+ BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
+\r
+ executor_.start();\r
}\r
\r
- std::wstring print() const\r
+ ~implementation() \r
{\r
- return L"flash_producer. filename: " + filename_;\r
+ executor_.invoke([this]{renderer_.reset();});\r
}\r
\r
- CComObject<flash::FlashAxContainer>* flashax_container_;\r
-\r
- concurrent_bounded_queue_r<safe_ptr<draw_frame>> frame_buffer_;\r
+ void param(const std::wstring& param) \r
+ { \r
+ if(!factory_)\r
+ BOOST_THROW_EXCEPTION(invalid_operation() << msg_info(narrow(print()) + "Uninitialized."));\r
\r
- safe_ptr<draw_frame> last_frame_;\r
+ executor_.invoke([&]\r
+ {\r
+ if(!renderer_)\r
+ renderer_.reset(factory_());\r
+ renderer_->param(param);\r
+ }, executor::high_priority);\r
+ }\r
+ \r
+ safe_ptr<draw_frame> receive()\r
+ {\r
+ auto frame = renderer_ ? renderer_->receive() : draw_frame::empty();\r
+ executor_.begin_invoke([this]\r
+ {\r
+ try\r
+ {\r
+ renderer_->render();\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ renderer_.reset();\r
+ }\r
+ });\r
+ return frame;\r
+ }\r
\r
- bitmap_ptr current_frame_;\r
- bitmap_ptr bmp_frame_;\r
+ void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
+ {\r
+ factory_ = [=]{return new flash_renderer(frame_processor, filename_);};\r
+ executor_.invoke([&]\r
+ {\r
+ if(!renderer_)\r
+ renderer_.reset(factory_());\r
+ });\r
+ }\r
\r
+ std::wstring print() const{ return L"flash[" + filename_ + L"]"; }\r
+ \r
std::wstring filename_;\r
- flash_producer* self_;\r
+ std::function<flash_renderer*()> factory_;\r
\r
- tbb::atomic<bool> is_empty_;\r
+ std::unique_ptr<flash_renderer> renderer_;\r
executor executor_;\r
- int invalid_count_;\r
-\r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
-\r
- video_format_desc format_desc_;\r
};\r
\r
flash_producer::flash_producer(flash_producer&& other) : impl_(std::move(other.impl_)){}\r
-flash_producer::flash_producer(const std::wstring& filename) : impl_(new implementation(this, filename)){}\r
+flash_producer::flash_producer(const std::wstring& filename) : impl_(new implementation(filename)){}\r
safe_ptr<draw_frame> flash_producer::receive(){return impl_->receive();}\r
void flash_producer::param(const std::wstring& param){impl_->param(param);}\r
void flash_producer::initialize(const safe_ptr<frame_processor_device>& frame_processor) { impl_->initialize(frame_processor);}\r
return L"";\r
}\r
\r
-safe_ptr<flash_producer> create_flash_producer(const std::vector<std::wstring>& params)\r
-{\r
- static const std::vector<std::wstring> extensions = list_of(L"swf");\r
- std::wstring filename = server::media_folder() + L"\\" + params[0];\r
- \r
- auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool\r
- {\r
- return boost::filesystem::is_regular_file(boost::filesystem::wpath(filename).replace_extension(ex));\r
- });\r
-\r
- if(ext == extensions.end())\r
- BOOST_THROW_EXCEPTION(file_not_found() << msg_info(narrow(filename)));\r
-\r
- return make_safe<flash_producer>(filename + L"." + *ext);\r
-}\r
-\r
}}}
\ No newline at end of file