]> git.sesse.net Git - casparcg/blob - modules/bluefish/consumer/bluefish_consumer.cpp
What the? somehow one of the mutex's got removed. - fixing
[casparcg] / modules / bluefish / consumer / bluefish_consumer.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21  
22 #include "../StdAfx.h"
23
24 #include "bluefish_consumer.h"
25 #include "../util/blue_velvet.h"
26 #include "../util/memory.h"
27
28 #include <core/video_format.h>
29 #include <core/frame/frame.h>
30 #include <core/frame/audio_channel_layout.h>
31 #include <core/help/help_repository.h>
32 #include <core/help/help_sink.h>
33
34 #include <common/executor.h>
35 #include <common/diagnostics/graph.h>
36 #include <common/array.h>
37 #include <common/memshfl.h>
38 #include <common/param.h>
39
40 #include <core/consumer/frame_consumer.h>
41 #include <core/mixer/audio/audio_util.h>
42
43 #include <tbb/concurrent_queue.h>
44 #include <tbb/atomic.h>
45
46 #include <common/assert.h>
47 #include <boost/lexical_cast.hpp>
48 #include <boost/timer.hpp>
49 #include <boost/range/algorithm.hpp>
50 #include <boost/property_tree/ptree.hpp>
51 #include <boost/algorithm/string.hpp>
52
53 #include <asmlib.h>
54
55 #include <memory>
56 #include <array>
57
58 namespace caspar { namespace bluefish { 
59                 
60 enum class hardware_downstream_keyer_mode
61 {
62         disable = 0,
63         external = 1,
64         internal = 2,           // Bluefish dedicated HW keyer - only available on some models.
65 };
66
67 enum class hardware_downstream_keyer_audio_source
68 {
69         SDIVideoInput = 1,
70         VideoOutputChannel = 2
71 };
72
73 enum class bluefish_hardware_output_channel
74 {
75         channel_a,
76         channel_b,
77         channel_c,
78         channel_d,
79         default_output_channel = channel_a
80 };
81
82 EBlueVideoChannel get_bluesdk_videochannel_from_streamid(bluefish_hardware_output_channel streamid)
83 {
84         /*This function would return the corresponding EBlueVideoChannel from the device output channel*/
85         switch (streamid)
86         {
87                 case bluefish_hardware_output_channel::channel_a:       return BLUE_VIDEO_OUTPUT_CHANNEL_A;
88                 case bluefish_hardware_output_channel::channel_b:       return BLUE_VIDEO_OUTPUT_CHANNEL_B;
89                 case bluefish_hardware_output_channel::channel_c:       return BLUE_VIDEO_OUTPUT_CHANNEL_C;
90                 case bluefish_hardware_output_channel::channel_d:       return BLUE_VIDEO_OUTPUT_CHANNEL_D;
91                 default: return BLUE_VIDEO_OUTPUT_CHANNEL_A;
92         }
93 }
94
95 bool get_videooutput_channel_routing_info_from_streamid(bluefish_hardware_output_channel streamid,
96         EEpochRoutingElements & channelSrcElement,
97         EEpochRoutingElements & sdioutputDstElement)
98 {
99         switch (streamid)
100         {
101         case bluefish_hardware_output_channel::channel_a:       channelSrcElement = EPOCH_SRC_OUTPUT_MEM_INTERFACE_CHA;
102                 sdioutputDstElement = EPOCH_DEST_SDI_OUTPUT_A;
103                 break;
104         case bluefish_hardware_output_channel::channel_b:       channelSrcElement = EPOCH_SRC_OUTPUT_MEM_INTERFACE_CHB;
105                 sdioutputDstElement = EPOCH_DEST_SDI_OUTPUT_B;
106                 break;
107         case bluefish_hardware_output_channel::channel_c:       channelSrcElement = EPOCH_SRC_OUTPUT_MEM_INTERFACE_CHC;
108                 sdioutputDstElement = EPOCH_DEST_SDI_OUTPUT_C;
109                 break;
110         case bluefish_hardware_output_channel::channel_d:       channelSrcElement = EPOCH_SRC_OUTPUT_MEM_INTERFACE_CHD;
111                 sdioutputDstElement = EPOCH_DEST_SDI_OUTPUT_D;
112                 break;
113         default: return false;
114         }
115         return true;
116 }
117
118 struct bluefish_consumer : boost::noncopyable
119 {
120         spl::shared_ptr<bvc_wrapper>                                            blue_;
121         const unsigned int                                                                      device_index_;
122         const core::video_format_desc                                           format_desc_;
123         const core::audio_channel_layout                                        channel_layout_;
124         core::audio_channel_remapper                                            channel_remapper_;
125         const int                                                                                       channel_index_;
126
127         const std::wstring                                                                      model_name_;
128
129         spl::shared_ptr<diagnostics::graph>                                     graph_;
130         boost::timer                                                                            frame_timer_;
131         boost::timer                                                                            tick_timer_;
132         boost::timer                                                                            sync_timer_;    
133                         
134         unsigned int                                                                            vid_fmt_;
135
136         std::array<blue_dma_buffer_ptr, 4>                                      all_frames_;    
137         std::queue<blue_dma_buffer_ptr>                                         reserved_frames_;
138         std::mutex                                                                                      reserved_frames_lock_;
139         std::queue<blue_dma_buffer_ptr>                                         live_frames_;
140         std::mutex                                                                                      live_frames_lock_;
141         std::shared_ptr<std::thread>                                            dma_present_thread_;
142         bool                                                                                            end_dma_thread_;
143
144         tbb::concurrent_bounded_queue<core::const_frame>        frame_buffer_;
145         tbb::atomic<int64_t>                                                            presentation_delay_millis_;
146         core::const_frame                                                                       previous_frame_                         = core::const_frame::empty();
147
148         const bool                                                                                      embedded_audio_;
149         const bool                                                                                      key_only_;
150                 
151         executor                                                                                        executor_;
152         hardware_downstream_keyer_mode                                          hardware_keyer_;
153         hardware_downstream_keyer_audio_source                          keyer_audio_source_;
154         bluefish_hardware_output_channel                                        device_output_channel_;
155 public:
156         bluefish_consumer(
157                         const core::video_format_desc& format_desc,
158                         const core::audio_channel_layout& in_channel_layout,
159                         const core::audio_channel_layout& out_channel_layout,
160                         int device_index,
161                         bool embedded_audio,
162                         bool key_only,
163                         hardware_downstream_keyer_mode keyer,
164                         hardware_downstream_keyer_audio_source keyer_audio_source,
165                         int channel_index,
166                         bluefish_hardware_output_channel device_output_channel)
167                 : blue_(create_blue(device_index))
168                 , device_index_(device_index)
169                 , format_desc_(format_desc)
170                 , channel_layout_(out_channel_layout)
171                 , channel_remapper_(in_channel_layout, out_channel_layout)
172                 , channel_index_(channel_index)
173                 , model_name_(get_card_desc(*blue_, device_index))
174                 , vid_fmt_(get_video_mode(*blue_, format_desc))
175                 , embedded_audio_(embedded_audio)
176                 , hardware_keyer_(keyer)
177                 , keyer_audio_source_(keyer_audio_source)
178                 , key_only_(key_only)
179                 , executor_(print())
180                 , device_output_channel_(device_output_channel)
181         {
182                 executor_.set_capacity(1);
183                 presentation_delay_millis_ = 0;
184
185                 graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
186                 graph_->set_color("sync-time", diagnostics::color(1.0f, 0.0f, 0.0f));
187                 graph_->set_color("frame-time", diagnostics::color(0.5f, 1.0f, 0.2f));
188                 graph_->set_text(print());
189                 diagnostics::register_graph(graph_);
190
191                 // Specify the video channel
192                 setup_hardware_output_channel();
193
194                 // Setting output Video mode
195                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_MODE, vid_fmt_)))
196                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set videomode."));
197
198                 // Select Update Mode for output
199                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_UPDATE_TYPE, UPD_FMT_FRAME)))
200                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set update type."));
201         
202                 disable_video_output();
203                 setup_hardware_output_channel_routing();
204                         
205                 //Select output memory format
206                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_MEMORY_FORMAT, MEM_FMT_ARGB_PC)))
207                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set memory format."));
208                 
209                 //Select image orientation
210                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))
211                         CASPAR_LOG(warning) << print() << L" Failed to set image orientation to normal.";       
212
213                 // Select data range
214                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_RGB_DATA_RANGE, CGR_RANGE)))
215                         CASPAR_LOG(warning) << print() << L" Failed to set RGB data range to CGR.";     
216                 
217                 if(!embedded_audio_ || (hardware_keyer_ == hardware_downstream_keyer_mode::internal && keyer_audio_source_ == hardware_downstream_keyer_audio_source::SDIVideoInput) )
218                 {
219                         if(BLUE_FAIL(blue_->set_card_property32(EMBEDEDDED_AUDIO_OUTPUT, 0)))
220                                 CASPAR_LOG(warning) << TEXT("BLUECARD ERROR: Failed to disable embedded audio.");                       
221                         CASPAR_LOG(info) << print() << TEXT(" Disabled embedded-audio.");
222                 }
223                 else
224                 {
225                         ULONG audio_value =
226                                 EMBEDDED_AUDIO_OUTPUT | blue_emb_audio_group1_enable;
227
228                         if (channel_layout_.num_channels > 4)
229                                 audio_value |= blue_emb_audio_group2_enable;
230
231                         if (channel_layout_.num_channels > 8)
232                                 audio_value |= blue_emb_audio_group3_enable;
233
234                         if (channel_layout_.num_channels > 12)
235                                 audio_value |= blue_emb_audio_group4_enable;
236
237                         if(BLUE_FAIL(blue_->set_card_property32(EMBEDEDDED_AUDIO_OUTPUT, audio_value)))
238                                 CASPAR_LOG(warning) << print() << TEXT(" Failed to enable embedded audio.");                    
239                         CASPAR_LOG(info) << print() << TEXT(" Enabled embedded-audio.");
240                 }
241
242                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_OUTPUT_ENGINE, VIDEO_ENGINE_PLAYBACK)))
243                         CASPAR_LOG(warning) << print() << TEXT(" Failed to set video engine.");
244
245                 if (is_epoch_card((*blue_)))
246                         setup_hardware_downstream_keyer(hardware_keyer_, keyer_audio_source_);
247
248                 enable_video_output();
249                                                 
250                 int n = 0;
251                 boost::range::generate(all_frames_, [&]{return std::make_shared<blue_dma_buffer>(static_cast<int>(format_desc_.size), n++);});
252         
253                 for (size_t i = 0; i < all_frames_.size(); i++)
254                         reserved_frames_.push(all_frames_[i]);
255         }
256
257         ~bluefish_consumer()
258         {
259                 try
260                 {
261                         executor_.invoke([&]
262                         {
263                                 end_dma_thread_ = true;
264                                 disable_video_output();
265                                 blue_->detach();        
266
267                                 if (dma_present_thread_)
268                                         dma_present_thread_->join();
269                         });
270                 }
271                 catch(...)
272                 {
273                         CASPAR_LOG_CURRENT_EXCEPTION();
274                 }
275         }
276
277         void setup_hardware_output_channel()
278         {
279                 // This function would be used to setup the logic video channel in the bluefish hardware
280                 EBlueVideoChannel out_vid_channel = get_bluesdk_videochannel_from_streamid(device_output_channel_);
281                 if (is_epoch_card((*blue_)))
282                 {
283                         if (out_vid_channel != BLUE_VIDEOCHANNEL_INVALID)
284                         {
285                                 if (BLUE_FAIL(blue_->set_card_property32(DEFAULT_VIDEO_OUTPUT_CHANNEL, out_vid_channel)))
286                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(" Failed to set video stream."));
287
288                                 blue_->video_playback_stop(0, 0);
289                         }
290                 }
291         }
292
293         void setup_hardware_output_channel_routing()
294         {
295                 //This function would be used to setup the dual link and any other routing that would be required .
296                 if (is_epoch_card(*blue_))
297                 {
298                         EBlueVideoChannel blueVideoOutputChannel = get_bluesdk_videochannel_from_streamid(device_output_channel_);
299                         EEpochRoutingElements src_element = (EEpochRoutingElements)0;
300                         EEpochRoutingElements dst_element = (EEpochRoutingElements)0;
301                         get_videooutput_channel_routing_info_from_streamid(device_output_channel_, src_element, dst_element);
302                         bool duallink_4224_enabled = false;
303
304                         if ((device_output_channel_ == bluefish_hardware_output_channel::channel_a || device_output_channel_ == bluefish_hardware_output_channel::channel_c) &&
305                                 (hardware_keyer_ == hardware_downstream_keyer_mode::external))
306                         {
307                                 duallink_4224_enabled = true;
308                         }
309
310                         // Enable/Disable dual link output
311                         if (BLUE_FAIL(blue_->set_card_property32(VIDEO_DUAL_LINK_OUTPUT, duallink_4224_enabled)))
312                                 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to enable/disable dual link."));
313
314                         if (!duallink_4224_enabled)
315                         {
316                                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_Independent_422)))
317                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set dual link format type to 4:2:2."));
318
319                                 ULONG routingValue = EPOCH_SET_ROUTING(src_element, dst_element, BLUE_CONNECTOR_PROP_SINGLE_LINK);
320                                 if (BLUE_FAIL(blue_->set_card_property32(MR2_ROUTING, routingValue)))
321                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(" Failed to MR 2 routing."));
322
323                                 // If single link 422, but on second channel AND on Neutron we need to set Genlock to Aux.
324                                 if (is_epoch_neutron_1i2o_card((*blue_)))               
325                                 {
326                                         if (blueVideoOutputChannel == BLUE_VIDEO_OUTPUT_CHANNEL_B)
327                                         {
328                                                 ULONG genLockSource = BlueGenlockAux;
329                                                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_GENLOCK_SIGNAL, genLockSource)))
330                                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to set GenLock to Aux Input."));
331                                         }
332                                 }
333                                 if (is_epoch_neutron_3o_card((*blue_)))
334                                 {
335                                         if (blueVideoOutputChannel == BLUE_VIDEO_OUTPUT_CHANNEL_C)
336                                         {
337                                                 ULONG genLockSource = BlueGenlockAux;
338                                                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_GENLOCK_SIGNAL, genLockSource)))
339                                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to set GenLock to Aux Input."));
340                                         }
341                                 }
342                         }
343                         else            // dual Link IS enabled, ie. 4224 Fill and Key
344                         {
345                                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))
346                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set dual link format type to 4:2:2:4."));
347
348                                 if (is_epoch_neutron_1i2o_card((*blue_)))               // Neutron cards require setting the Genlock conector to Aux to enable them to do Dual-Link
349                                 {
350                                         ULONG genLockSource = BlueGenlockAux;
351                                         if (BLUE_FAIL(blue_->set_card_property32(VIDEO_GENLOCK_SIGNAL, genLockSource)))
352                                                 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to set GenLock to Aux Input."));
353                                 }
354                                 else if (is_epoch_neutron_3o_card((*blue_)))
355                                 {
356                                         if (blueVideoOutputChannel == BLUE_VIDEO_OUTPUT_CHANNEL_C)
357                                         {
358                                                 ULONG genLockSource = BlueGenlockAux;
359                                                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_GENLOCK_SIGNAL, genLockSource)))
360                                                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to set GenLock to Aux Input."));
361                                         }
362                                 }
363                         }
364                 }
365         }
366
367         void setup_hardware_downstream_keyer(hardware_downstream_keyer_mode keyer, hardware_downstream_keyer_audio_source audio_source)
368         {
369                 unsigned int keyer_control_value = 0, card_feature_value = 0;
370                 unsigned int card_connector_value = 0;
371                 unsigned int nOutputStreams = 0;
372                 unsigned int nInputStreams = 0;
373                 unsigned int nInputSDIConnector = 0;
374                 unsigned int nOutputSDIConnector = 0;
375                 if (BLUE_OK(blue_->get_card_property32(CARD_FEATURE_STREAM_INFO, card_feature_value)))
376                 {
377                         nOutputStreams = CARD_FEATURE_GET_SDI_OUTPUT_STREAM_COUNT(card_feature_value);
378                         nInputStreams = CARD_FEATURE_GET_SDI_INPUT_STREAM_COUNT(card_feature_value);
379                 }
380                 if (BLUE_OK(blue_->get_card_property32(CARD_FEATURE_CONNECTOR_INFO, card_connector_value)))
381                 {
382                         nOutputSDIConnector = CARD_FEATURE_GET_SDI_OUTPUT_CONNECTOR_COUNT(card_connector_value);
383                         nInputSDIConnector = CARD_FEATURE_GET_SDI_INPUT_CONNECTOR_COUNT(card_connector_value);
384                 }
385                 if (nInputSDIConnector == 0 || nInputStreams == 0)
386                         return;
387
388                 if (keyer == hardware_downstream_keyer_mode::disable || keyer == hardware_downstream_keyer_mode::external)
389                 {
390                         keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_DISABLED(keyer_control_value);
391                         keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_DISABLE_OVER_BLACK(keyer_control_value);
392                 }
393                 else if (keyer == hardware_downstream_keyer_mode::internal)
394                 {
395                         unsigned int invalidVideoModeFlag = 0;
396                         unsigned int inputVideoSignal = 0;
397                         if (BLUE_FAIL(blue_->get_card_property32(INVALID_VIDEO_MODE_FLAG, invalidVideoModeFlag)))
398                                 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(" Failed to get invalid video mode flag"));
399
400                         keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_ENABLED(keyer_control_value);
401                         if (BLUE_FAIL(blue_->get_card_property32(VIDEO_INPUT_SIGNAL_VIDEO_MODE, inputVideoSignal)))
402                                 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(" Failed to get video input signal mode"));
403
404                         if (inputVideoSignal >= invalidVideoModeFlag)
405                                 keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_ENABLE_OVER_BLACK(keyer_control_value);
406                         else
407                                 keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_DISABLE_OVER_BLACK(keyer_control_value);
408                 
409                         // lock to input
410                         if (BLUE_FAIL(blue_->set_card_property32(VIDEO_GENLOCK_SIGNAL, BlueSDI_A_BNC)))
411                                 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(" Failed to set the genlock to the input for the HW keyer"));
412                 }
413
414                 if (audio_source == hardware_downstream_keyer_audio_source::SDIVideoInput && (keyer == hardware_downstream_keyer_mode::internal))
415                         keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_USE_INPUT_ANCILLARY(keyer_control_value);
416                 else if (audio_source == hardware_downstream_keyer_audio_source::VideoOutputChannel)
417                         keyer_control_value = VIDEO_ONBOARD_KEYER_SET_STATUS_USE_OUTPUT_ANCILLARY(keyer_control_value);
418
419                 if (BLUE_FAIL(blue_->set_card_property32(VIDEO_ONBOARD_KEYER, keyer_control_value)))
420                         CASPAR_LOG(error) << print() << TEXT(" Failed to set keyer control.");
421         }
422
423         void enable_video_output()
424         {
425                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_BLACKGENERATOR, 0)))
426                         CASPAR_LOG(error) << print() << TEXT(" Failed to disable video output.");       
427         }
428
429         void disable_video_output()
430         {
431                 blue_->video_playback_stop(0,0);
432                 if(BLUE_FAIL(blue_->set_card_property32(VIDEO_BLACKGENERATOR, 1)))
433                         CASPAR_LOG(error)<< print() << TEXT(" Failed to disable video output.");        
434                 if (BLUE_FAIL(blue_->set_card_property32(EMBEDEDDED_AUDIO_OUTPUT, 0)))
435                         CASPAR_LOG(error) << print() << TEXT(" Failed to disable audio output.");
436
437         }
438         
439         std::future<bool> send(core::const_frame& frame)
440         {                               
441                 return executor_.begin_invoke([=]() -> bool
442                 {
443                         try
444                         {       
445                                 display_frame(frame);                           
446                                 graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()*format_desc_.fps*0.5));
447                                 tick_timer_.restart();
448                         }
449                         catch(...)
450                         {
451                                 CASPAR_LOG_CURRENT_EXCEPTION();
452                         }
453
454                         return true;
455                 });
456         }
457
458         static void dma_present_thread_actual(void* arg)
459         {
460                 bluefish_consumer* blue = (bluefish_consumer*)arg;
461
462                 bvc_wrapper wait_b;
463                 wait_b.attach(blue->device_index_);
464                 EBlueVideoChannel out_vid_channel = get_bluesdk_videochannel_from_streamid(blue->device_output_channel_);
465                 wait_b.set_card_property32(DEFAULT_VIDEO_OUTPUT_CHANNEL, out_vid_channel);
466                 int frames_to_buffer = 3;
467                 unsigned long buffer_id = 0;
468                 unsigned long underrun = 0;
469
470                 while (!blue->end_dma_thread_)
471                 {
472                         if (blue->live_frames_.size() && BLUE_OK(blue->blue_->video_playback_allocate(buffer_id, underrun)))
473                         {
474                                 blue->live_frames_lock_.lock();
475                                 blue_dma_buffer_ptr buf = blue->live_frames_.front();
476                                 blue->live_frames_.pop();
477                                 blue->live_frames_lock_.unlock();
478
479                                 // Send and display
480                                 if (blue->embedded_audio_)
481                                 {
482                                         // Do video first, then encode hanc, then do hanc DMA...
483                                         blue->blue_->system_buffer_write(const_cast<uint8_t*>(buf->image_data()),
484                                                 static_cast<unsigned long>(buf->image_size()),
485                                                 BlueImage_HANC_DMABuffer(buffer_id, BLUE_DATA_IMAGE),
486                                                 0);
487
488                                         blue->blue_->system_buffer_write(buf->hanc_data(),
489                                                 static_cast<unsigned long>(buf->hanc_size()),
490                                                 BlueImage_HANC_DMABuffer(buffer_id, BLUE_DATA_HANC),
491                                                 0);
492
493                                         if (BLUE_FAIL(blue->blue_->video_playback_present(BlueBuffer_Image_HANC(buffer_id), 1, 0, 0)))
494                                         {
495                                                 CASPAR_LOG(warning) << blue->print() << TEXT(" video_playback_present failed.");
496                                         }
497                                 }
498                                 else
499                                 {
500                                         blue->blue_->system_buffer_write(const_cast<uint8_t*>(buf->image_data()),
501                                                 static_cast<unsigned long>(buf->image_size()),
502                                                 BlueImage_DMABuffer(buffer_id, BLUE_DATA_IMAGE),
503                                                 0);
504
505                                         if (BLUE_FAIL(blue->blue_->video_playback_present(BlueBuffer_Image(buffer_id), 1, 0, 0)))
506                                                 CASPAR_LOG(warning) << blue->print() << TEXT(" video_playback_present failed.");
507                                 }
508
509                                 //                              blue->graph_->set_value("frame-time", static_cast<float>(blue->frame_timer_.elapsed()*blue->format_desc_.fps*0.5));
510
511                                 blue->reserved_frames_lock_.lock();
512                                 blue->reserved_frames_.push(buf);
513                                 blue->reserved_frames_lock_.unlock();
514                         }
515                         else
516                         {
517                                 // do WFS       
518                                 unsigned long n_field = 0;
519                                 wait_b.wait_video_output_sync(UPD_FMT_FRAME, n_field);
520                         }
521
522                         if (frames_to_buffer > 0)
523                         {
524                                 frames_to_buffer--;
525                                 if (frames_to_buffer == 0)
526                                 {
527                                         if (BLUE_FAIL(blue->blue_->video_playback_start(0, 0)))
528                                                 CASPAR_LOG(warning) << blue->print() << TEXT("Error video playback start failed");
529                                 }
530                         }
531                 }
532                 wait_b.detach();
533         }
534
535         void display_frame(core::const_frame frame)
536         {
537                 frame_timer_.restart();         
538
539                 if (previous_frame_ != core::const_frame::empty())
540                         presentation_delay_millis_ = previous_frame_.get_age_millis();
541
542                 previous_frame_ = frame;
543
544                 // Copy to local buffers
545                 if (reserved_frames_.size())
546                 {
547                         reserved_frames_lock_.lock();
548                         blue_dma_buffer_ptr buf = reserved_frames_.front();
549                         reserved_frames_.pop();
550                         reserved_frames_lock_.unlock();
551                         void* dest = buf->image_data();
552
553                         if (!frame.image_data().empty())
554                         {
555                                 if (key_only_)
556                                         aligned_memshfl(dest, frame.image_data().begin(), frame.image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);
557                                 else
558                                         A_memcpy(dest, frame.image_data().begin(), frame.image_data().size());
559                         }
560                         else
561                                 A_memset(dest, 0, reserved_frames_.front()->image_size());
562
563                         frame_timer_.restart();
564
565                         // remap, encode and copy hanc data
566                         if (embedded_audio_)
567                         {
568                                 auto remapped_audio = channel_remapper_.mix_and_rearrange(frame.audio_data());
569                                 auto frame_audio = core::audio_32_to_24(remapped_audio);
570                                 encode_hanc(reinterpret_cast<BLUE_UINT32*>(buf->hanc_data()),
571                                         frame_audio.data(),
572                                         static_cast<int>(frame.audio_data().size() / channel_layout_.num_channels),
573                                         static_cast<int>(channel_layout_.num_channels));
574                         }
575
576                         live_frames_lock_.lock();
577                         live_frames_.push(buf);
578                         live_frames_lock_.unlock();
579
580                         // start the thread if required.
581                         if (dma_present_thread_ == 0)
582                         {
583                                 end_dma_thread_ = false;
584                                 dma_present_thread_ = std::make_shared<std::thread>(&dma_present_thread_actual, this);
585 #if defined(_WIN32)
586                                 HANDLE handle = (HANDLE)dma_present_thread_->native_handle();
587                                 SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST);
588 #endif
589                         }
590                 }
591                 graph_->set_value("frame-time", static_cast<float>(frame_timer_.elapsed()*format_desc_.fps*0.5));
592
593                 // Sync
594                 sync_timer_.restart();
595                 unsigned long n_field = 0;
596                 blue_->wait_video_output_sync(UPD_FMT_FRAME, n_field);
597                 graph_->set_value("sync-time", sync_timer_.elapsed()*format_desc_.fps*0.5);
598         }
599
600         void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, int audio_samples, int audio_nchannels)
601         {       
602                 const auto sample_type = AUDIO_CHANNEL_24BIT | AUDIO_CHANNEL_LITTLEENDIAN;
603                 auto emb_audio_flag = blue_emb_audio_enable | blue_emb_audio_group1_enable;
604
605                 if (audio_nchannels > 4)
606                         emb_audio_flag |= blue_emb_audio_group2_enable;
607
608                 if (audio_nchannels > 8)
609                         emb_audio_flag |= blue_emb_audio_group3_enable;
610
611                 if (audio_nchannels > 12)
612                         emb_audio_flag |= blue_emb_audio_group4_enable;
613                 
614                 hanc_stream_info_struct hanc_stream_info;
615                 memset(&hanc_stream_info, 0, sizeof(hanc_stream_info));
616                 
617                 hanc_stream_info.AudioDBNArray[0] = -1;
618                 hanc_stream_info.AudioDBNArray[1] = -1;
619                 hanc_stream_info.AudioDBNArray[2] = -1;
620                 hanc_stream_info.AudioDBNArray[3] = -1;
621                 hanc_stream_info.hanc_data_ptr    = hanc_data;
622                 hanc_stream_info.video_mode               = vid_fmt_;           
623                 
624                 int cardType = CRD_INVALID;
625                 blue_->query_card_type(cardType, device_index_);
626                 blue_->encode_hanc_frame(cardType, &hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);
627         }
628         
629         std::wstring print() const
630         {
631                 return model_name_ + L" [" + boost::lexical_cast<std::wstring>(channel_index_) + L"-" + 
632                         boost::lexical_cast<std::wstring>(device_index_) + L"|" +  format_desc_.name + L"]";
633         }
634
635         int64_t presentation_delay_millis() const
636         {
637                 return presentation_delay_millis_;
638         }
639 };
640
641 struct bluefish_consumer_proxy : public core::frame_consumer
642 {
643         core::monitor::subject                                  monitor_subject_;
644
645         std::unique_ptr<bluefish_consumer>              consumer_;
646         const int                                                               device_index_;
647         const bool                                                              embedded_audio_;
648         const bool                                                              key_only_;
649
650         std::vector<int>                                                audio_cadence_;
651         core::video_format_desc                                 format_desc_;
652         core::audio_channel_layout                              in_channel_layout_              = core::audio_channel_layout::invalid();
653         core::audio_channel_layout                              out_channel_layout_;
654         hardware_downstream_keyer_mode                  hardware_keyer_;
655         hardware_downstream_keyer_audio_source  hardware_keyer_audio_source_;
656         bluefish_hardware_output_channel                hardware_output_channel_;
657
658 public:
659
660         bluefish_consumer_proxy(int device_index, 
661                                                         bool embedded_audio, 
662                                                         bool key_only, 
663                                                         hardware_downstream_keyer_mode keyer,
664                                                         hardware_downstream_keyer_audio_source keyer_audio_source,
665                                                         const core::audio_channel_layout& out_channel_layout,
666                                                         bluefish_hardware_output_channel hardware_output_channel)
667
668                 : device_index_(device_index)
669                 , embedded_audio_(embedded_audio)
670                 , key_only_(key_only)
671                 , hardware_keyer_(keyer)
672                 , hardware_keyer_audio_source_(keyer_audio_source)
673                 , out_channel_layout_(out_channel_layout)
674                 , hardware_output_channel_(hardware_output_channel)
675         {
676         }
677         
678         // frame_consumer
679         
680         void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int channel_index) override
681         {
682                 format_desc_            = format_desc;
683                 in_channel_layout_      = channel_layout;
684                 audio_cadence_          = format_desc.audio_cadence;
685
686                 if (out_channel_layout_ == core::audio_channel_layout::invalid())
687                         out_channel_layout_ = in_channel_layout_;
688
689                 consumer_.reset();
690                 consumer_.reset(new bluefish_consumer(  format_desc, 
691                                                                                                 in_channel_layout_, 
692                                                                                                 out_channel_layout_, 
693                                                                                                 device_index_, 
694                                                                                                 embedded_audio_, 
695                                                                                                 key_only_, 
696                                                                                                 hardware_keyer_,
697                                                                                                 hardware_keyer_audio_source_, 
698                                                                                                 channel_index,
699                                                                                                 hardware_output_channel_));
700         }
701         
702         std::future<bool> send(core::const_frame frame) override
703         {
704                 CASPAR_VERIFY(audio_cadence_.front() * in_channel_layout_.num_channels == static_cast<size_t>(frame.audio_data().size()));
705                 boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
706                 return consumer_->send(frame);
707         }
708                 
709         std::wstring print() const override
710         {
711                 return consumer_ ? consumer_->print() : L"[bluefish_consumer]";
712         }
713
714         std::wstring name() const override
715         {
716                 return L"bluefish";
717         }
718
719         boost::property_tree::wptree info() const override
720         {
721                 boost::property_tree::wptree info;
722                 info.add(L"type", L"bluefish");
723                 info.add(L"key-only", key_only_);
724                 info.add(L"device", device_index_);
725                 info.add(L"embedded-audio", embedded_audio_);
726                 info.add(L"presentation-frame-age", presentation_frame_age_millis());
727                 return info;
728         }
729
730         int buffer_depth() const override
731         {
732                 return 1;
733         }
734         
735         int index() const override
736         {
737                 return 400 + device_index_;
738         }
739
740         int64_t presentation_frame_age_millis() const override
741         {
742                 return consumer_ ? consumer_->presentation_delay_millis() : 0;
743         }
744
745         core::monitor::subject& monitor_output()
746         {
747                 return monitor_subject_;
748         }
749 };      
750
751
752 void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
753 {
754         sink.short_description(L"Sends video on an SDI output using Bluefish video cards.");
755         sink.syntax(L"BLUEFISH {[device_index:int]|1} {[sdi_device:int]|a} {[embedded_audio:EMBEDDED_AUDIO]} {[key_only:KEY_ONLY]} {CHANNEL_LAYOUT [channel_layout:string]} {[keyer:string|disabled]} ");
756         sink.para()
757                 ->text(L"Sends video on an SDI output using Bluefish video cards. Multiple devices can be ")
758                 ->text(L"installed in the same machine and used at the same time, they will be addressed via ")
759                 ->text(L"different ")->code(L"device_index")->text(L" parameters.");
760         sink.para()->text(L"Multiple output channels can be accessed via the ")->code(L"sdi_device")->text(L" parameter.");
761         sink.para()->text(L"Specify ")->code(L"embedded_audio")->text(L" to embed audio into the SDI signal.");
762         sink.para()
763                 ->text(L"Specifying ")->code(L"key_only")->text(L" will extract only the alpha channel from the ")
764                 ->text(L"channel. This is useful when you have two SDI video cards, and neither has native support ")
765                 ->text(L"for separate fill/key output");
766         sink.para()->text(L"Specify ")->code(L"channel_layout")->text(L" to output a different audio channel layout than the channel uses.");
767         sink.para()->text(L"Specify ")->code(L"keyer")->text(L" to control the output channel configuration and hardware keyer")
768                 ->text(L"disabled results in a single SDI stream of 422 output - This is the default")
769                 ->text(L"external results in a 4224 stream across 2 SDI connectors, ")
770                 ->text(L"internal results in a 422 output keyed over the incoming SDI input using the dedicated hardware keyer on the Bleufish hadrware");
771         sink.para()->text(L"Specify ")->code(L"internal-keyer-audio-source")->text(L" to control the source of the audio and ANC data when using the internal/hardware keyer");
772
773         sink.para()->text(L"Examples:");
774         sink.example(L">> ADD 1 BLUEFISH", L"uses the default device_index of 1.");
775         sink.example(L">> ADD 1 BLUEFISH 2", L"for device_index 2.");
776         sink.example(
777                 L">> ADD 1 BLUEFISH 1 EMBEDDED_AUDIO\n"
778
779                 L">> ADD 1 BLUEFISH 2 KEY_ONLY", L"uses device with index 1 as fill output with audio and device with index 2 as key output.");
780
781 }
782
783
784 spl::shared_ptr<core::frame_consumer> create_consumer(  const std::vector<std::wstring>& params,
785                                                                                                                 core::interaction_sink*,
786                                                                                                                 std::vector<spl::shared_ptr<core::video_channel>> channels)
787 {
788         if(params.size() < 1 || !boost::iequals(params.at(0), L"BLUEFISH"))
789                 return core::frame_consumer::empty();
790
791         const auto device_index                 = params.size() > 1 ? boost::lexical_cast<int>(params.at(1)) : 1;
792         const auto device_stream                = contains_param(       L"SDI-STREAM", params);
793         const auto embedded_audio               = contains_param(       L"EMBEDDED_AUDIO",      params);
794         const auto key_only                             = contains_param(       L"KEY_ONLY",            params);
795         const auto channel_layout               = get_param(            L"CHANNEL_LAYOUT",      params);
796         const auto keyer_option                 = contains_param(       L"KEYER",                       params);
797         const auto keyer_audio_option   = contains_param(       L"INTERNAL-KEYER-AUDIO-SOURCE", params);
798
799         auto layout = core::audio_channel_layout::invalid();
800
801         if (!channel_layout.empty())
802         {
803                 auto found_layout = core::audio_channel_layout_repository::get_default()->get_layout(channel_layout);
804
805                 if (!found_layout)
806                         CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Channel layout " + channel_layout + L" not found"));
807
808                 layout = *found_layout;
809         }
810
811         bluefish_hardware_output_channel device_output_channel = bluefish_hardware_output_channel::channel_a;
812         if (contains_param(L"A", params))
813                 device_output_channel = bluefish_hardware_output_channel::channel_a;
814         else if (contains_param(L"B", params))
815                 device_output_channel = bluefish_hardware_output_channel::channel_b;
816         else if (contains_param(L"C", params))
817                 device_output_channel = bluefish_hardware_output_channel::channel_c;
818         else if (contains_param(L"D", params))
819                 device_output_channel = bluefish_hardware_output_channel::channel_d;
820
821         hardware_downstream_keyer_mode keyer = hardware_downstream_keyer_mode::disable;
822         if (contains_param(L"DISABLED", params))
823                 keyer = hardware_downstream_keyer_mode::disable;
824         else if (contains_param(L"EXTERNAL", params))
825                 keyer = hardware_downstream_keyer_mode::external;
826         else if (contains_param(L"INTERNAL", params))
827                 keyer = hardware_downstream_keyer_mode::internal;
828
829         hardware_downstream_keyer_audio_source keyer_audio_source = hardware_downstream_keyer_audio_source::VideoOutputChannel;
830         if (contains_param(L"SDIVIDEOINPUT", params))
831                 keyer_audio_source = hardware_downstream_keyer_audio_source::SDIVideoInput;
832         else
833         if (contains_param(L"VIDEOOUTPUTCHANNEL", params))
834                 keyer_audio_source = hardware_downstream_keyer_audio_source::VideoOutputChannel;
835
836         return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only, keyer, keyer_audio_source, layout, device_output_channel);
837 }
838
839 spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
840                                                                                         const boost::property_tree::wptree& ptree, core::interaction_sink*,
841                                                                                         std::vector<spl::shared_ptr<core::video_channel>> channels)
842 {       
843         const auto device_index         = ptree.get(                                            L"device",                      1);
844         const auto device_stream        = ptree.get(                                            L"sdi-stream", L"a");
845         const auto embedded_audio       = ptree.get(                                            L"embedded-audio",      false);
846         const auto key_only                     = ptree.get(                                            L"key-only",            false);
847         const auto channel_layout       = ptree.get_optional<std::wstring>(     L"channel-layout");
848         const auto hardware_keyer_value = ptree.get(                                    L"keyer", L"disabled");
849         const auto keyer_audio_source_value = ptree.get(                                L"internal-keyer-audio-source", L"videooutputchannel");
850         
851         auto layout = core::audio_channel_layout::invalid();
852
853         if (channel_layout)
854         {
855                 CASPAR_SCOPED_CONTEXT_MSG("/channel-layout")
856
857                 auto found_layout = core::audio_channel_layout_repository::get_default()->get_layout(*channel_layout);
858
859                 if (!found_layout)
860                         CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Channel layout " + *channel_layout + L" not found"));
861
862                 layout = *found_layout;
863         }
864
865         bluefish_hardware_output_channel device_output_channel = bluefish_hardware_output_channel::channel_a;
866         if (device_stream == L"a")
867                 device_output_channel = bluefish_hardware_output_channel::channel_a;
868         else if (device_stream == L"b")
869                 device_output_channel = bluefish_hardware_output_channel::channel_b;
870         else if (device_stream == L"c")
871                 device_output_channel = bluefish_hardware_output_channel::channel_c;
872         else if (device_stream == L"d")
873                 device_output_channel = bluefish_hardware_output_channel::channel_d;
874
875         hardware_downstream_keyer_mode keyer_mode = hardware_downstream_keyer_mode::disable;
876         if (hardware_keyer_value == L"disabled")
877                 keyer_mode = hardware_downstream_keyer_mode::disable;
878         else if (hardware_keyer_value == L"external")
879                 keyer_mode = hardware_downstream_keyer_mode::external;
880         else if (hardware_keyer_value == L"internal")
881                 keyer_mode = hardware_downstream_keyer_mode::internal;
882
883         hardware_downstream_keyer_audio_source keyer_audio_source = hardware_downstream_keyer_audio_source::VideoOutputChannel;
884         if (keyer_audio_source_value == L"videooutputchannel")
885                 keyer_audio_source = hardware_downstream_keyer_audio_source::VideoOutputChannel;
886         else
887                 if (keyer_audio_source_value == L"sdivideoinput")
888                         keyer_audio_source = hardware_downstream_keyer_audio_source::SDIVideoInput;
889
890         return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only, keyer_mode, keyer_audio_source, layout, device_output_channel);
891 }
892
893 }}