]> git.sesse.net Git - casparcg/blobdiff - core/consumer/bluefish/bluefish_consumer.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / core / consumer / bluefish / bluefish_consumer.cpp
index ae7da5c88135a2695b1764887524f7ece2a6749d..2c1f4be8b8809e43434ea59fed372b851a05bb30 100644 (file)
 *\r
 */\r
  \r
-#include "..\..\StdAfx.h"\r
+#include "../../StdAfx.h"\r
 \r
-#ifndef DISABLE_BLUEFISH\r
-\r
-#include "fwd.h"\r
 #include "bluefish_consumer.h"\r
 #include "util.h"\r
-#include "exception.h"\r
 #include "memory.h"\r
 \r
-#include "../../processor/write_frame.h"\r
+#include <mixer/frame/read_frame.h>\r
 \r
-#include <boost/thread.hpp>\r
+#include <common/concurrency/executor.h>\r
+#include <common/diagnostics/graph.h>\r
+#include <common/utility/timer.h>\r
 \r
 #include <tbb/concurrent_queue.h>\r
 \r
 #include <BlueVelvet4.h>\r
 #include <BlueHancUtils.h>\r
 \r
-namespace caspar { namespace core { namespace bluefish {\r
+#include <windows.h>\r
+\r
+#include <boost/thread/once.hpp>\r
+\r
+#include <memory>\r
+\r
+namespace caspar { namespace core {\r
        \r
-struct consumer::implementation\r
+CBlueVelvet4* (*BlueVelvetFactory4)();\r
+BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag);\r
+BLUE_UINT32 (*encode_hanc_frame_ex)(BLUE_UINT32 card_type, struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr, BLUE_UINT32 no_audio_ch,    BLUE_UINT32 no_audio_samples, BLUE_UINT32 nTypeOfSample, BLUE_UINT32 emb_audio_flag);\r
+\r
+void blue_velvet_initialize()\r
+{\r
+#ifdef _DEBUG\r
+       auto module = LoadLibrary(L"BlueVelvet3_d.dll");\r
+#else\r
+       auto module = LoadLibrary(L"BlueVelvet3.dll");\r
+#endif\r
+       if(!module)\r
+               BOOST_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueVelvet3.dll"));\r
+       static std::shared_ptr<void> lib(module, FreeLibrary);\r
+       BlueVelvetFactory4 = reinterpret_cast<decltype(BlueVelvetFactory4)>(GetProcAddress(module, "BlueVelvetFactory4"));\r
+}\r
+\r
+void blue_hanc_initialize()\r
+{\r
+#ifdef _DEBUG\r
+       auto module = LoadLibrary(L"BlueHancUtils_d.dll");\r
+#else\r
+       auto module = LoadLibrary(L"BlueHancUtils.dll");\r
+#endif\r
+       if(!module)\r
+               BOOST_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueHancUtils.dll"));\r
+       static std::shared_ptr<void> lib(module, FreeLibrary);\r
+       encode_hanc_frame = reinterpret_cast<decltype(encode_hanc_frame)>(GetProcAddress(module, "encode_hanc_frame"));\r
+       encode_hanc_frame_ex = reinterpret_cast<decltype(encode_hanc_frame_ex)>(GetProcAddress(module, "encode_hanc_frame_ex"));\r
+}\r
+\r
+void blue_initialize()\r
 {\r
-       implementation::implementation(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) \r
-               : device_index_(device_index), format_desc_(format_desc), sdk_(BlueVelvetFactory4()), current_id_(0), embed_audio_(embed_audio)\r
+       blue_velvet_initialize();\r
+       blue_hanc_initialize();\r
+}\r
+               \r
+struct bluefish_consumer::implementation : boost::noncopyable\r
+{\r
+       safe_ptr<diagnostics::graph> graph_;\r
+       timer perf_timer_;\r
+\r
+       boost::unique_future<void> active_;\r
+                       \r
+       std::shared_ptr<CBlueVelvet4> blue_;\r
+       \r
+       const unsigned int device_index_;\r
+       video_format_desc format_desc_;\r
+               \r
+       unsigned long   mem_fmt_;\r
+       unsigned long   upd_fmt_;\r
+       EVideoMode              vid_fmt_; \r
+       unsigned long   res_fmt_; \r
+       unsigned long   engine_mode_;\r
+       \r
+       std::array<blue_dma_buffer_ptr, 3> reserved_frames_;    \r
+\r
+       const bool embed_audio_;\r
+\r
+       executor executor_;\r
+public:\r
+       implementation::implementation(unsigned int device_index, bool embed_audio) \r
+               : graph_(diagnostics::create_graph("bluefish"))\r
+               , device_index_(device_index)           \r
+               , mem_fmt_(MEM_FMT_ARGB_PC)\r
+               , upd_fmt_(UPD_FMT_FRAME)\r
+               , vid_fmt_(VID_FMT_INVALID) \r
+               , res_fmt_(RES_FMT_NORMAL) \r
+               , engine_mode_(VIDEO_ENGINE_FRAMESTORE)         \r
+               , embed_audio_(embed_audio)\r
        {\r
-               mem_fmt_                = MEM_FMT_ARGB_PC;\r
-               upd_fmt_                = UPD_FMT_FRAME;\r
-               vid_fmt_                = VID_FMT_PAL; \r
-               res_fmt_                = RES_FMT_NORMAL; \r
-               engine_mode_    = VIDEO_ENGINE_FRAMESTORE;\r
-                               \r
-               if(BLUE_FAIL(sdk_->device_attach(device_index_, FALSE))) \r
+               graph_->add_guide("frame_time_target", 0.5, diagnostics::color(0.5f, 0.0f, 0.0f));\r
+               graph_->set_color("frame_time", diagnostics::color(1.0f, 0.0f, 0.0f));  \r
+       }\r
+\r
+       ~implementation()\r
+       {\r
+               if(executor_.is_running())\r
+               {\r
+                       executor_.invoke([&]\r
+                       {\r
+                               disable_video_output();\r
+\r
+                               if(blue_)\r
+                                       blue_->device_detach();         \r
+               });\r
+               }\r
+\r
+               CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << device_index_;\r
+       }\r
+\r
+       void initialize(const video_format_desc& format_desc)\r
+       {\r
+               static boost::once_flag flag = BOOST_ONCE_INIT;\r
+               boost::call_once(blue_initialize, flag);        \r
+               \r
+               format_desc_ = format_desc;\r
+\r
+               blue_.reset(BlueVelvetFactory4());\r
+\r
+               if(BLUE_FAIL(blue_->device_attach(device_index_, FALSE))) \r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to attach device."));\r
        \r
-               int videoCardType = sdk_->has_video_cardtype();\r
+               int videoCardType = blue_->has_video_cardtype();\r
                CASPAR_LOG(info) << TEXT("BLUECARD INFO: Card type: ") << get_card_desc(videoCardType) << TEXT(". (device ") << device_index_ << TEXT(")");\r
        \r
                //void* pBlueDevice = blue_attach_to_device(1);\r
@@ -65,12 +158,11 @@ struct consumer::implementation
                //blue_set_connector_property(pBlueDevice, 1, video_routing);\r
                //blue_detach_from_device(&pBlueDevice);\r
                \r
-               vid_fmt_ = VID_FMT_INVALID;\r
                auto desiredVideoFormat = vid_fmt_from_video_format(format_desc_.format);\r
-               int videoModeCount = sdk_->count_video_mode();\r
-               for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) \r
+               int videoModeCount = blue_->count_video_mode();\r
+               for(int videoModeIndex = 1; videoModeIndex <= videoModeCount; ++videoModeIndex) \r
                {\r
-                       EVideoMode videoMode = sdk_->enum_video_mode(videoModeIndex);\r
+                       EVideoMode videoMode = blue_->enum_video_mode(videoModeIndex);\r
                        if(videoMode == desiredVideoFormat) \r
                                vid_fmt_ = videoMode;                   \r
                }\r
@@ -78,234 +170,197 @@ struct consumer::implementation
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode."));\r
                \r
                // Set default video output channel\r
-               //if(BLUE_FAIL(set_card_property(sdk_, DEFAULT_VIDEO_OUTPUT_CHANNEL, channel)))\r
+               //if(BLUE_FAIL(set_card_property(blue_, DEFAULT_VIDEO_OUTPUT_CHANNEL, channel)))\r
                //      CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set default channel. (device ") << device_index_ << TEXT(")");\r
 \r
                //Setting output Video mode\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MODE, vid_fmt_))) \r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MODE, vid_fmt_))) \r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set videomode."));\r
 \r
                //Select Update Mode for output\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_UPDATE_TYPE, upd_fmt_))) \r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_UPDATE_TYPE, upd_fmt_))) \r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set update type. "));\r
        \r
                disable_video_output();\r
 \r
                //Enable dual link output\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT, 1)))\r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT, 1)))\r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to enable dual link."));\r
 \r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))\r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))\r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set dual link format type to 4:2:2:4. (device " + boost::lexical_cast<std::string>(device_index_) + ")"));\r
                        \r
                //Select output memory format\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_MEMORY_FORMAT, mem_fmt_))) \r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MEMORY_FORMAT, mem_fmt_))) \r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set memory format."));\r
                \r
                //Select image orientation\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))\r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))\r
                        CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set image orientation to normal. (device ") << device_index_ << TEXT(")"); \r
 \r
                // Select data range\r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) \r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) \r
                        CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set RGB data range to CGR. (device ") << device_index_ << TEXT(")");       \r
                \r
-               if(BLUE_FAIL(set_card_property(sdk_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR)))\r
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR)))\r
                        CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to set colormatrix to ") << (vid_fmt_ == VID_FMT_PAL ? TEXT("601 CGR") : TEXT("709 CGR")) << TEXT(". (device ") << device_index_ << TEXT(")");\r
-               \r
-               //if(BLUE_FAIL(set_card_property(sdk_, EMBEDDED_AUDIO_OUTPUT, 0)))      \r
-               //      CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to enable embedded audio. (device ") << device_index_ << TEXT(")");   \r
-               //else \r
-               //{\r
-               //      CASPAR_LOG(info) << TEXT("BLUECARD INFO: Enabled embedded audio. (device ") << device_index_ << TEXT(")");\r
-               //      hasEmbeddedAudio_ = true;\r
-               //}\r
+\r
+               if(!embed_audio_)\r
+               {\r
+                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, 0))) \r
+                               CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to disable embedded audio. (device ") << device_index_ << TEXT(")");                  \r
+                       CASPAR_LOG(info) << TEXT("BLUECARD INFO: Disabled embedded-audio. device ") << device_index_ << TEXT(")");\r
+               }\r
+               else\r
+               {\r
+                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, blue_emb_audio_enable | blue_emb_audio_group1_enable))) \r
+                               CASPAR_LOG(error) << TEXT("BLUECARD ERROR: Failed to enable embedded audio. (device ") << device_index_ << TEXT(")");                   \r
+                       CASPAR_LOG(info) << TEXT("BLUECARD INFO: Enabled embedded-audio. device ") << device_index_ << TEXT(")");\r
+               }\r
 \r
                CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << format_desc_ << TEXT(". (device ") << device_index_ << TEXT(")");\r
 \r
-               if (sdk_->has_output_key()) \r
+               if (blue_->has_output_key()) \r
                {\r
                        int dummy = TRUE; int v4444 = FALSE; int invert = FALSE; int white = FALSE;\r
-                       sdk_->set_output_key(dummy, v4444, invert, white);\r
+                       blue_->set_output_key(dummy, v4444, invert, white);\r
                }\r
 \r
-               if(sdk_->GetHDCardType(device_index_) != CRD_HD_INVALID) \r
-                       sdk_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI);   \r
+               if(blue_->GetHDCardType(device_index_) != CRD_HD_INVALID) \r
+                       blue_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI);  \r
        \r
-               if(BLUE_FAIL(sdk_->set_video_engine(engine_mode_)))\r
+               if(BLUE_FAIL(blue_->set_video_engine(engine_mode_)))\r
                        BOOST_THROW_EXCEPTION(bluefish_exception() << msg_info("BLUECARD ERROR: Failed to set vido engine."));\r
 \r
                enable_video_output();\r
                                                \r
-               page_locked_buffer::reserve_working_size(MAX_HANC_BUFFER_SIZE * hanc_buffers_.size());          \r
-               for(size_t n = 0; n < hanc_buffers_.size(); ++n)\r
-                       hanc_buffers_[n] = std::make_shared<page_locked_buffer>(MAX_HANC_BUFFER_SIZE);\r
+               for(size_t n = 0; n < reserved_frames_.size(); ++n)\r
+                       reserved_frames_[n] = std::make_shared<blue_dma_buffer>(format_desc_.size, n);          \r
+                               \r
+               executor_.start();\r
 \r
-               frame_buffer_.set_capacity(1);\r
-               thread_ = boost::thread([=]{run();});\r
-               \r
                CASPAR_LOG(info) << TEXT("BLUECARD INFO: Successfully initialized device ") << device_index_;\r
-       }\r
-\r
-       ~implementation()\r
-       {\r
-               frame_buffer_.push(nullptr);\r
-               thread_.join();\r
-\r
-               disable_video_output();\r
 \r
-               if(sdk_)\r
-                       sdk_->device_detach();          \r
-\r
-               CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << device_index_;\r
+               active_ = executor_.begin_invoke([]{});\r
        }\r
        \r
        void enable_video_output()\r
        {\r
-               if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 0)))\r
+               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 0)))\r
                        CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")");  \r
        }\r
 \r
        void disable_video_output()\r
        {\r
-               if(!BLUE_PASS(set_card_property(sdk_, VIDEO_BLACKGENERATOR, 1)))\r
+               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 1)))\r
                        CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")");          \r
        }\r
 \r
-       void display(const consumer_frame& frame)\r
-       {\r
-               if(exception_ != nullptr)\r
-                       std::rethrow_exception(exception_);\r
-\r
-               frame_buffer_.push(std::make_shared<consumer_frame>(frame));\r
-       }\r
-\r
-       void do_display(consumer_frame_ptr& frame)\r
-       {\r
-               try\r
+       virtual void send(const safe_ptr<const read_frame>& frame)\r
+       {                       \r
+               static std::vector<short> silence(MAX_HANC_BUFFER_SIZE, 0);\r
+               \r
+               size_t audio_samples = static_cast<size_t>(48000.0 / format_desc_.fps);\r
+               size_t audio_nchannels = 2;\r
+               \r
+               active_.get();\r
+               active_ = executor_.begin_invoke([=]\r
                {\r
-                       auto hanc = hanc_buffers_.front();              \r
-                       std::rotate(hanc_buffers_.begin(), hanc_buffers_.begin() + 1, hanc_buffers_.end());\r
-                       \r
-                       static size_t audio_samples = 1920;\r
-                       static size_t audio_nchannels = 2;\r
-                       static std::vector<short> silence(audio_samples*audio_nchannels*2, 0);\r
+                       try\r
+                       {\r
+                               perf_timer_.reset();\r
 \r
+                               std::copy_n(frame->image_data().begin(), frame->image_data().size(), reserved_frames_.front()->image_data());\r
 \r
-                       unsigned long fieldCount = 0;\r
-                       sdk_->wait_output_video_synch(UPD_FMT_FRAME, fieldCount);\r
+                               unsigned long n_field = 0;\r
+                               blue_->wait_output_video_synch(UPD_FMT_FRAME, n_field);\r
                                \r
-                       if(embed_audio_)\r
-                       {               \r
-                               auto& frame_audio_data = frame->audio_data().empty() ? silence : frame->audio_data();\r
+                               if(embed_audio_)\r
+                               {               \r
+                                       auto frame_audio_data = frame->audio_data().empty() ? silence.data() : const_cast<short*>(frame->audio_data().begin());\r
 \r
-                               encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), const_cast<short*>(frame_audio_data.data()), audio_samples, audio_nchannels);\r
+                                       encode_hanc(reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()), frame_audio_data, audio_samples, audio_nchannels);\r
                                                                \r
-                               sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->data().begin()), \r
-                                                                                                frame->data().size(), \r
-                                                                                                nullptr, \r
-                                                                                                BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
-\r
-                               sdk_->system_buffer_write_async(hanc->data(),\r
-                                                                                                hanc->size(), \r
-                                                                                                nullptr,                 \r
-                                                                                                BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_HANC));\r
-\r
-                               if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image_HANC(current_id_))))\r
-                                       CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
+                                       blue_->system_buffer_write_async(const_cast<unsigned char*>(reserved_frames_.front()->image_data()), \r
+                                                                                                       reserved_frames_.front()->image_size(), \r
+                                                                                                       nullptr, \r
+                                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
+\r
+                                       blue_->system_buffer_write_async(reserved_frames_.front()->hanc_data(),\r
+                                                                                                       reserved_frames_.front()->hanc_size(), \r
+                                                                                                       nullptr,                 \r
+                                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_HANC));\r
+\r
+                                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image_HANC(reserved_frames_.front()->id()))))\r
+                                               CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
+                               }\r
+                               else\r
+                               {\r
+                                       blue_->system_buffer_write_async(const_cast<unsigned char*>(reserved_frames_.front()->image_data()),\r
+                                                                                                       reserved_frames_.front()->image_size(), \r
+                                                                                                       nullptr,                 \r
+                                                                                                       BlueImage_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
+                       \r
+                                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image(reserved_frames_.front()->id()))))\r
+                                               CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
+                               }\r
+\r
+                               std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
+                               graph_->update("frame_time", static_cast<float>((perf_timer_.elapsed()-format_desc_.interval)/format_desc_.interval*0.5));\r
                        }\r
-                       else\r
+                       catch(...)\r
                        {\r
-                               sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->data().begin()),\r
-                                                                                                frame->data().size(), \r
-                                                                                                nullptr,                 \r
-                                                                                                BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
-                       \r
-                               if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image(current_id_))))\r
-                                       CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
                        }\r
-\r
-                       transferring_frame_ = frame;\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
+               });\r
        }\r
 \r
+       virtual size_t buffer_depth() const{return 1;}\r
 \r
        void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, size_t audio_samples, size_t audio_nchannels)\r
        {       \r
-               auto card_type = sdk_->has_video_cardtype();\r
+               auto card_type = blue_->has_video_cardtype();\r
                auto sample_type = (AUDIO_CHANNEL_16BIT | AUDIO_CHANNEL_LITTLEENDIAN);\r
                \r
                hanc_stream_info_struct hanc_stream_info;\r
                memset(&hanc_stream_info, 0, sizeof(hanc_stream_info));\r
-\r
-               std::fill_n(hanc_stream_info.AudioDBNArray, sizeof(hanc_stream_info.AudioDBNArray)/sizeof(*hanc_stream_info.AudioDBNArray), -1);\r
+               \r
+               hanc_stream_info.AudioDBNArray[0] = -1;\r
+               hanc_stream_info.AudioDBNArray[1] = -1;\r
+               hanc_stream_info.AudioDBNArray[2] = -1;\r
+               hanc_stream_info.AudioDBNArray[3] = -1;\r
                hanc_stream_info.hanc_data_ptr = hanc_data;\r
                hanc_stream_info.video_mode = vid_fmt_;\r
                \r
                auto emb_audio_flag = (blue_emb_audio_enable | blue_emb_audio_group1_enable);\r
 \r
                if (!is_epoch_card(card_type))\r
-               {\r
-                       encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, \r
-                                                               audio_samples, sample_type, emb_audio_flag);    \r
-               }\r
+                       encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);  \r
                else\r
-               {\r
-                       encode_hanc_frame_ex(card_type, &hanc_stream_info, audio_data, audio_nchannels,\r
-                                                                audio_samples, sample_type, emb_audio_flag);\r
-               }                                               \r
+                       encode_hanc_frame_ex(card_type, &hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);\r
        }\r
+};\r
 \r
-       void run()\r
-       {\r
-               while(true)\r
-               {\r
-                       try\r
-                       {\r
-                               consumer_frame_ptr frame;\r
-                               frame_buffer_.pop(frame);\r
-\r
-                               if(!frame)\r
-                                       return;\r
-\r
-                               do_display(frame);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               exception_ = std::current_exception();\r
-                       }\r
-               }       \r
-       }\r
-               \r
-       BlueVelvetPtr sdk_;\r
+bluefish_consumer::bluefish_consumer(bluefish_consumer&& other) : impl_(std::move(other.impl_)){}\r
+bluefish_consumer::bluefish_consumer(unsigned int device_index, bool embed_audio) : impl_(new implementation(device_index, embed_audio)){}     \r
+void bluefish_consumer::initialize(const video_format_desc& format_desc){impl_->initialize(format_desc);}\r
+void bluefish_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t bluefish_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
        \r
-       unsigned int device_index_;\r
-       video_format_desc format_desc_;\r
-       \r
-       std::exception_ptr exception_;\r
-       boost::thread thread_;\r
-       tbb::concurrent_bounded_queue<consumer_frame_ptr> frame_buffer_;\r
-       \r
-       unsigned long   mem_fmt_;\r
-       unsigned long   upd_fmt_;\r
-       EVideoMode              vid_fmt_; \r
-       unsigned long   res_fmt_; \r
-       unsigned long   engine_mode_;\r
-\r
-       consumer_frame_ptr transferring_frame_;\r
-\r
-       std::array<page_locked_buffer_ptr, 3> hanc_buffers_;\r
-       int current_id_;\r
-       bool embed_audio_;\r
-};\r
+safe_ptr<frame_consumer> create_bluefish_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 1 || params[0] != L"BLUEFISH")\r
+               return frame_consumer::empty();\r
+               \r
+       int device_index = 1;\r
+       bool embed_audio = false;\r
 \r
-consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){}    \r
-void consumer::display(const consumer_frame& frame){impl_->display(frame);}\r
+       try{if(params.size() > 1) device_index = boost::lexical_cast<int>(params[2]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+       try{if(params.size() > 2) embed_audio = boost::lexical_cast<bool>(params[3]);}\r
+       catch(boost::bad_lexical_cast&){}\r
 \r
-}}}\r
+       return make_safe<bluefish_consumer>(device_index, embed_audio);\r
+}\r
 \r
-#endif
\ No newline at end of file
+}}
\ No newline at end of file