]> git.sesse.net Git - casparcg/blob - core/consumer/bluefish/BlueFishVideoConsumer.cpp
1c02aea1e5e740e9d3471d9054d9faba9f044e7d
[casparcg] / core / consumer / bluefish / BlueFishVideoConsumer.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\r
6 *    CasparCG is free software: you can redistribute it and/or modify\r
7 *    it under the terms of the GNU General Public License as published by\r
8 *    the Free Software Foundation, either version 3 of the License, or\r
9 *    (at your option) any later version.\r
10 *\r
11 *    CasparCG is distributed in the hope that it will be useful,\r
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 *    GNU General Public License for more details.\r
15 \r
16 *    You should have received a copy of the GNU General Public License\r
17 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 */\r
20  \r
21 #include "..\..\StdAfx.h"\r
22 \r
23 #ifndef DISABLE_BLUEFISH\r
24 \r
25 #include <BlueVelvet4.h>\r
26 #include "BlueFishVideoConsumer.h"\r
27 #include "BluefishPlaybackStrategy.h"\r
28 \r
29 #include <stdlib.h>\r
30 #include <stdio.h>\r
31 \r
32 #if defined(_MSC_VER)\r
33 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
34 #endif\r
35 \r
36 namespace caspar {\r
37 namespace bluefish {\r
38 \r
39 ///////////////////////////////////////////\r
40 // BlueFishVideoConsumer::EnumerateDevices\r
41 // RETURNS: Number of identified bluefish-cards\r
42 int BlueFishVideoConsumer::EnumerateDevices()\r
43 {\r
44         CASPAR_LOG(info) << "Bleufhsi SDK version: " << BlueVelvetVersion;\r
45         BlueVelvetPtr pSDK(BlueVelvetFactory4());\r
46 \r
47         if(pSDK != 0) {\r
48                 int deviceCount = 0;\r
49                 pSDK->device_enumerate(deviceCount);\r
50                 return deviceCount;\r
51         }\r
52         else\r
53                 return 0;\r
54 }\r
55 \r
56 \r
57 ///////////////////////////////////////////\r
58 // BlueFishVideoConsumer::Create\r
59 // PARAMS: deviceIndex(index of the card that is to be wrapped in a consumer)\r
60 // RETURNS: a new BlueFishVideoConsumer-object for the specified card\r
61 // COMMENT: Creates and initializes a consumer that outputs video to a bluefish-card\r
62 frame_consumer_ptr BlueFishVideoConsumer::Create(const frame_format_desc& format_desc, unsigned int deviceIndex)\r
63 {\r
64         BlueFishFrameConsumerPtr card(new BlueFishVideoConsumer(format_desc));\r
65         if(card != 0 && card->SetupDevice(deviceIndex) == false)\r
66                 card.reset();\r
67 \r
68         return card;\r
69 }\r
70 \r
71 ////////////////////////////////////////\r
72 // BlueFishVideoConsumer constructor\r
73 BlueFishVideoConsumer::BlueFishVideoConsumer(const frame_format_desc& format_desc) : format_desc_(format_desc), pSDK_(BlueVelvetFactory4()), currentFormat_(frame_format::pal), _deviceIndex(0), hasEmbeddedAudio_(false)\r
74 {\r
75         frameBuffer_.set_capacity(1);\r
76         thread_ = boost::thread([=]{Run();});\r
77 }\r
78 \r
79 ////////////////////////////////////////\r
80 // BlueFishVideoConsumer destructor\r
81 BlueFishVideoConsumer::~BlueFishVideoConsumer()\r
82 {\r
83         frameBuffer_.push(nullptr),\r
84         thread_.join();\r
85         ReleaseDevice();\r
86 }\r
87 \r
88 /*******************/\r
89 /**    METHODS    **/\r
90 /*******************/\r
91 \r
92 unsigned long BlueFishVideoConsumer::VidFmtFromFrameFormat(frame_format fmt) \r
93 {\r
94         switch(fmt)\r
95         {\r
96         case frame_format::pal:                 return VID_FMT_PAL;\r
97         case frame_format::ntsc:                return VID_FMT_NTSC;\r
98         case frame_format::x576p2500:   return ULONG_MAX;       //not supported\r
99         case frame_format::x720p5000:   return VID_FMT_720P_5000;\r
100         case frame_format::x720p5994:   return VID_FMT_720P_5994;\r
101         case frame_format::x720p6000:   return VID_FMT_720P_6000;\r
102         case frame_format::x1080p2397:  return VID_FMT_1080P_2397;\r
103         case frame_format::x1080p2400:  return VID_FMT_1080P_2400;\r
104         case frame_format::x1080i5000:  return VID_FMT_1080I_5000;\r
105         case frame_format::x1080i5994:  return VID_FMT_1080I_5994;\r
106         case frame_format::x1080i6000:  return VID_FMT_1080I_6000;\r
107         case frame_format::x1080p2500:  return VID_FMT_1080P_2500;\r
108         case frame_format::x1080p2997:  return VID_FMT_1080P_2997;\r
109         case frame_format::x1080p3000:  return VID_FMT_1080P_3000;\r
110         default:                                                return ULONG_MAX;\r
111         }\r
112 }\r
113 \r
114 TCHAR* GetBluefishCardDesc(int cardType) \r
115 {\r
116         switch(cardType) \r
117         {\r
118         case CRD_BLUEDEEP_LT:                           return TEXT("Deepblue LT"); // D64 Lite\r
119         case CRD_BLUEDEEP_SD:                           return TEXT("Iridium SD"); // Iridium SD\r
120         case CRD_BLUEDEEP_AV:                           return TEXT("Iridium AV"); // Iridium AV\r
121         case CRD_BLUEDEEP_IO:                           return TEXT("Deepblue IO"); // D64 Full\r
122         case CRD_BLUEWILD_AV:                           return TEXT("Wildblue AV"); // D64 AV\r
123         case CRD_IRIDIUM_HD:                            return TEXT("Iridium HD"); // * Iridium HD\r
124         case CRD_BLUEWILD_RT:                           return TEXT("Wildblue RT"); // D64 RT\r
125         case CRD_BLUEWILD_HD:                           return TEXT("Wildblue HD"); // * BadAss G2\r
126         case CRD_REDDEVIL:                                      return TEXT("Iridium Full"); // Iridium Full\r
127         case CRD_BLUEDEEP_HD:                                                                                                            // * BadAss G2 variant, proposed, reserved\r
128         case CRD_BLUEDEEP_HDS:                          return TEXT("Reserved for \"BasAss G2"); // * BadAss G2 variant, proposed, reserved\r
129         case CRD_BLUE_ENVY:                                     return TEXT("Blue envy"); // Mini Din \r
130         case CRD_BLUE_PRIDE:                            return TEXT("Blue pride"); //Mini Din Output \r
131         case CRD_BLUE_GREED:                            return TEXT("Blue greed");\r
132         case CRD_BLUE_INGEST:                           return TEXT("Blue ingest");\r
133         case CRD_BLUE_SD_DUALLINK:                      return TEXT("Blue SD duallink");\r
134         case CRD_BLUE_CATALYST:                         return TEXT("Blue catalyst");\r
135         case CRD_BLUE_SD_DUALLINK_PRO:          return TEXT("Blue SD duallink pro");\r
136         case CRD_BLUE_SD_INGEST_PRO:            return TEXT("Blue SD ingest pro");\r
137         case CRD_BLUE_SD_DEEPBLUE_LITE_PRO:     return TEXT("Blue SD deepblue lite pro");\r
138         case CRD_BLUE_SD_SINGLELINK_PRO:        return TEXT("Blue SD singlelink pro");\r
139         case CRD_BLUE_SD_IRIDIUM_AV_PRO:        return TEXT("Blue SD iridium AV pro");\r
140         case CRD_BLUE_SD_FIDELITY:                      return TEXT("Blue SD fidelity");\r
141         case CRD_BLUE_SD_FOCUS:                         return TEXT("Blue SD focus");\r
142         case CRD_BLUE_SD_PRIME:                         return TEXT("Blue SD prime");\r
143         case CRD_BLUE_EPOCH_2K_CORE:            return TEXT("Blue epoch 2k core");\r
144         case CRD_BLUE_EPOCH_2K_ULTRA:           return TEXT("Blue epoch 2k ultra");\r
145         case CRD_BLUE_EPOCH_HORIZON:            return TEXT("Blue epoch horizon");\r
146         case CRD_BLUE_EPOCH_CORE:                       return TEXT("Blue epoch core");\r
147         case CRD_BLUE_EPOCH_ULTRA:                      return TEXT("Blue epoch ultra");\r
148         case CRD_BLUE_CREATE_HD:                        return TEXT("Blue create HD");\r
149         case CRD_BLUE_CREATE_2K:                        return TEXT("Blue create 2k");\r
150         case CRD_BLUE_CREATE_2K_ULTRA:          return TEXT("Blue create 2k ultra");\r
151         default:                                                        return TEXT("Unknown");\r
152         }\r
153 }\r
154 \r
155 bool BlueFishVideoConsumer::SetupDevice(unsigned int deviceIndex)\r
156 {\r
157         return this->DoSetupDevice(deviceIndex);\r
158 }\r
159 \r
160 /*\r
161 // Original initialization code\r
162 bool BlueFishVideoConsumer::DoSetupDevice(unsigned int deviceIndex, std::wstring strDesiredFrameFormat)\r
163 {\r
164         _deviceIndex = deviceIndex;\r
165 \r
166         unsigned long memFmt = MEM_FMT_ARGB_PC, updFmt = UPD_FMT_FRAME, vidFmt = VID_FMT_PAL, resFmt = RES_FMT_NORMAL;\r
167         unsigned long desiredVideoFormat = VID_FMT_PAL;\r
168         int iDummy;\r
169 \r
170         int bufferIndex=0;      //Bufferindex used when initializing the buffers\r
171 \r
172         if(strDesiredFrameFormat.size() == 0)\r
173                 strDesiredFrameFormat = TEXT("PAL");\r
174 \r
175         frame_format casparVideoFormat = caspar::get_video_format(strDesiredFrameFormat);\r
176         desiredVideoFormat = BlueFishVideoConsumer::VidFmtFromFrameFormat(casparVideoFormat);\r
177         currentFormat_ = casparVideoFormat != FFormatInvalid ? casparVideoFormat : FFormatPAL;\r
178         if(desiredVideoFormat == ULONG_MAX) {\r
179                 LOG << TEXT("BLUECARD ERROR: Unsupported videomode: ") << strDesiredFrameFormat << TEXT(". (device") << _deviceIndex << TEXT(")");\r
180                 return false;\r
181         }\r
182 \r
183         if(BLUE_FAIL(pSDK_->device_attach(_deviceIndex, FALSE))) {\r
184                 LOG << TEXT("BLUECARD ERROR: Failed to attach device") << _deviceIndex;\r
185                 return false;\r
186         }\r
187 \r
188         if(desiredVideoFormat != VID_FMT_PAL) {\r
189                 int videoModeCount = pSDK_->count_video_mode();\r
190                 for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) {\r
191                         EVideoMode videoMode = pSDK_->enum_video_mode(videoModeIndex);\r
192                         if(videoMode == desiredVideoFormat) {\r
193                                 vidFmt = videoMode;\r
194                         }\r
195                 }\r
196         }\r
197 \r
198         if(vidFmt == VID_FMT_PAL) {\r
199                 strDesiredFrameFormat = TEXT("PAL");\r
200                 currentFormat_ = FFormatPAL;\r
201         }\r
202 \r
203         if(BLUE_FAIL(pSDK_->set_video_framestore_style(vidFmt, memFmt, updFmt, resFmt))) {\r
204                 LOG << TEXT("BLUECARD ERROR: Failed to set videomode to ") << strDesiredFrameFormat << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
205                 return false;\r
206         }\r
207 \r
208         LOG << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << strDesiredFrameFormat << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
209 \r
210         if (pSDK_->has_output_key()) {\r
211                 iDummy = TRUE;\r
212                 int v4444 = FALSE, invert = FALSE, white = FALSE;\r
213                 pSDK_->set_output_key(iDummy, v4444, invert, white);\r
214         }\r
215 \r
216         if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) {\r
217                 pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI);\r
218         }\r
219 \r
220 \r
221         iDummy = FALSE;\r
222         pSDK_->set_vertical_flip(iDummy);\r
223 \r
224         // Get framestore parameters\r
225         if(BLUE_OK(pSDK_->render_buffer_sizeof(m_bufferCount, m_length, m_actual, m_golden))) {\r
226                 LOG << TEXT("BLUECARD INFO: Buffers: ") << m_bufferCount << TEXT(", \"Length\": ") << m_length << TEXT(", Buffer size: ") << m_actual << TEXT(" (device ") << _deviceIndex << TEXT(")") << common::LogStream::Flush;\r
227         }\r
228         else {\r
229                 LOG << TEXT("BLUECARD ERROR: Failed to get framestore parameters (device ") << _deviceIndex << TEXT(")");\r
230         }\r
231 \r
232         pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, m_golden));\r
233 \r
234         iDummy = TRUE;\r
235         pSDK_->set_output_video(iDummy);\r
236 \r
237         // Now specify video output buffer\r
238         pSDK_->render_buffer_update(0);\r
239 \r
240         pPlaybackControl_.reset(new FramePlaybackControl(FramePlaybackStrategyPtr(new BluefishPlaybackStrategy(this))));\r
241         pPlaybackControl_->Start();\r
242 \r
243         LOG << TEXT("BLUECARD INFO: Successfully initialized device ") << _deviceIndex;\r
244         return true;\r
245 }\r
246 */\r
247 \r
248 //New, improved(?) initialization code. \r
249 //Based on code sent from the bluefish-sdk support 2009-08-25. Email "RE: [sdk] Ang. RE: Issue with SD Lite Pro PCI-E"\r
250 bool BlueFishVideoConsumer::DoSetupDevice(unsigned int deviceIndex)\r
251 {\r
252         _deviceIndex = deviceIndex;\r
253 \r
254         unsigned long memFmt = MEM_FMT_ARGB_PC, updFmt = UPD_FMT_FRAME, vidFmt = VID_FMT_PAL, resFmt = RES_FMT_NORMAL, engineMode = VIDEO_ENGINE_FRAMESTORE;\r
255         unsigned long desiredVideoFormat = VID_FMT_PAL;\r
256         int iDummy;\r
257 \r
258         int bufferIndex=0;      //Bufferindex used when initializing the buffers\r
259 \r
260         if(BLUE_FAIL(pSDK_->device_attach(_deviceIndex, FALSE))) {\r
261                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to attach device. (device " << _deviceIndex << TEXT(")");\r
262                 return false;\r
263         }\r
264 \r
265         int videoCardType = pSDK_->has_video_cardtype();\r
266         CASPAR_LOG(info) << "BLUECARD INFO: Card type: " << GetBluefishCardDesc(videoCardType) << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
267 \r
268         desiredVideoFormat = BlueFishVideoConsumer::VidFmtFromFrameFormat(format_desc_.format);\r
269         currentFormat_ = format_desc_.format != frame_format::invalid ? format_desc_.format : frame_format::pal;\r
270         if(desiredVideoFormat == ULONG_MAX) {\r
271                 CASPAR_LOG(error) << "BLUECARD ERROR: Unsupported videomode: " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
272                 return false;\r
273         }\r
274 \r
275         if(desiredVideoFormat != VID_FMT_PAL) {\r
276                 int videoModeCount = pSDK_->count_video_mode();\r
277                 for(int videoModeIndex=1; videoModeIndex <= videoModeCount; ++videoModeIndex) {\r
278                         EVideoMode videoMode = pSDK_->enum_video_mode(videoModeIndex);\r
279                         if(videoMode == desiredVideoFormat) {\r
280                                 vidFmt = videoMode;\r
281                         }\r
282                 }\r
283         }\r
284 \r
285         if(vidFmt != desiredVideoFormat) {\r
286                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set desired videomode: " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
287         }\r
288 \r
289         if(vidFmt == VID_FMT_PAL) {\r
290                 currentFormat_ = frame_format::pal;\r
291                 format_desc_ = frame_format_desc::format_descs[frame_format::pal];\r
292         }\r
293 \r
294         DisableVideoOutput();\r
295 \r
296         VARIANT value;\r
297         value.vt = VT_UI4;\r
298 \r
299         //Enable dual link output\r
300         value.ulVal = 1;\r
301         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_DUAL_LINK_OUTPUT, value))) {\r
302                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to enable dual link. (device " << _deviceIndex << TEXT(")");\r
303                 return false;\r
304         }\r
305 \r
306         value.ulVal = Signal_FormatType_4224;\r
307         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, value))) {\r
308                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set dual link format type to 4:2:2:4. (device " << _deviceIndex << TEXT(")");\r
309                 return false;\r
310         }\r
311 \r
312         //Setting output Video mode\r
313         value.ulVal = vidFmt;\r
314         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_MODE, value))) {\r
315                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set videomode. (device " << _deviceIndex << TEXT(")");\r
316                 return false;\r
317         }\r
318 \r
319         //Select Update Mode for output\r
320         value.ulVal = updFmt;\r
321         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_UPDATE_TYPE, value))) {\r
322                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set update type. (device " << _deviceIndex << TEXT(")");\r
323                 return false;\r
324         }\r
325         \r
326         //Select output memory format\r
327         value.ulVal = memFmt;\r
328         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_MEMORY_FORMAT, value))) {\r
329                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set memory format. (device " << _deviceIndex << TEXT(")");\r
330                 return false;\r
331         }\r
332 \r
333         //SELECT IMAGE ORIENTATION\r
334         value.ulVal = ImageOrientation_Normal;\r
335         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_IMAGE_ORIENTATION, value))) {\r
336                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set image orientation to normal. (device " << _deviceIndex << TEXT(")");\r
337         }\r
338 \r
339         value.ulVal = CGR_RANGE;\r
340         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_RGB_DATA_RANGE, value))) {\r
341                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set RGB data range to CGR. (device " << _deviceIndex << TEXT(")");\r
342         }\r
343 \r
344         value.ulVal = MATRIX_709_CGR;\r
345         if(vidFmt == VID_FMT_PAL) {\r
346                 value.ulVal = MATRIX_601_CGR;\r
347         }\r
348         if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_PREDEFINED_COLOR_MATRIX, value))) {\r
349                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set colormatrix to " << (vidFmt == VID_FMT_PAL ? TEXT("601 CGR") : TEXT("709 CGR")) << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
350         }\r
351         \r
352 \r
353         //Disable embedded audio\r
354         value.ulVal = 1;\r
355         if(!BLUE_PASS(pSDK_->SetCardProperty(EMBEDDED_AUDIO_OUTPUT, value))) {\r
356                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to enable embedded audio. (device " << _deviceIndex << TEXT(")");\r
357         }\r
358         else {\r
359                 CASPAR_LOG(info) << "BLUECARD INFO: Enabled embedded audio. (device " << _deviceIndex << TEXT(")");\r
360                 hasEmbeddedAudio_ = true;\r
361         }\r
362 \r
363         CASPAR_LOG(info) << "BLUECARD INFO: Successfully configured bluecard for " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")");\r
364 \r
365         if (pSDK_->has_output_key()) {\r
366                 iDummy = TRUE;\r
367                 int v4444 = FALSE, invert = FALSE, white = FALSE;\r
368                 pSDK_->set_output_key(iDummy, v4444, invert, white);\r
369         }\r
370 \r
371         if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) {\r
372                 pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI);\r
373         }\r
374 \r
375         ULONG videoGolden = BlueVelvetGolden(vidFmt, memFmt, updFmt);\r
376 \r
377         pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, videoGolden));\r
378 \r
379         pPlayback_ = std::make_shared<BluefishPlaybackStrategy>(this);\r
380 \r
381         if(BLUE_FAIL(pSDK_->set_video_engine(engineMode))) {\r
382                 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set vido engine. (device " << _deviceIndex << TEXT(")");\r
383                 return false;\r
384         }\r
385 \r
386         EnableVideoOutput();\r
387 \r
388         CASPAR_LOG(info) << "BLUECARD INFO: Successfully initialized device " << _deviceIndex;\r
389         return true;\r
390 }\r
391 \r
392 bool BlueFishVideoConsumer::ReleaseDevice()\r
393 {\r
394         pPlayback_.reset();\r
395 \r
396         pFrameManager_.reset();\r
397         DisableVideoOutput();\r
398 \r
399         if(pSDK_) {\r
400                 pSDK_->device_detach();\r
401         }\r
402 \r
403         CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << _deviceIndex;\r
404         return true;\r
405 }\r
406 \r
407 void BlueFishVideoConsumer::EnableVideoOutput()\r
408 {\r
409         //Need sync. protection?\r
410         if(pSDK_)\r
411         {\r
412                 VARIANT value;\r
413                 value.vt = VT_UI4;\r
414 \r
415                 //Deactivate channel\r
416                 value.ulVal = 0;\r
417                 if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_BLACKGENERATOR, value))) {\r
418                         CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << _deviceIndex << TEXT(")");\r
419                 }\r
420         }\r
421 }\r
422 \r
423 void BlueFishVideoConsumer::DisableVideoOutput()\r
424 {\r
425         //Need sync. protection?\r
426         if(pSDK_)\r
427         {\r
428                 VARIANT value;\r
429                 value.vt = VT_UI4;\r
430 \r
431                 //Deactivate channel\r
432                 value.ulVal = 1;\r
433                 if(!BLUE_PASS(pSDK_->SetCardProperty(VIDEO_BLACKGENERATOR, value))) {\r
434                         CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << _deviceIndex << TEXT(")");\r
435                 }\r
436         }\r
437 }\r
438 \r
439 void BlueFishVideoConsumer::display(const gpu_frame_ptr& frame)\r
440 {\r
441         if(frame == nullptr)\r
442                 return;\r
443 \r
444         if(pException_ != nullptr)\r
445                 std::rethrow_exception(pException_);\r
446 \r
447         frameBuffer_.push(frame);\r
448 }\r
449 \r
450 void BlueFishVideoConsumer::Run()\r
451 {\r
452         while(true)\r
453         {\r
454                 try\r
455                 {\r
456                         gpu_frame_ptr frame;\r
457                         frameBuffer_.pop(frame);\r
458                         if(frame == nullptr)\r
459                                 return;\r
460 \r
461                         pPlayback_->display(frame);\r
462                 }\r
463                 catch(...)\r
464                 {\r
465                         pException_ = std::current_exception();\r
466                 }\r
467         }       \r
468 }\r
469 \r
470 }}\r
471 \r
472 #endif