2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\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
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
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
21 #include "..\..\StdAfx.h"
\r
23 #ifndef DISABLE_BLUEFISH
\r
25 #include <BlueVelvet4.h>
\r
26 #include "BlueFishVideoConsumer.h"
\r
27 #include "BluefishPlaybackStrategy.h"
\r
32 #if defined(_MSC_VER)
\r
33 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
\r
37 namespace bluefish {
\r
39 ///////////////////////////////////////////
\r
40 // BlueFishVideoConsumer::EnumerateDevices
\r
41 // RETURNS: Number of identified bluefish-cards
\r
42 int BlueFishVideoConsumer::EnumerateDevices()
\r
44 CASPAR_LOG(info) << "Bleufhsi SDK version: " << BlueVelvetVersion;
\r
45 BlueVelvetPtr pSDK(BlueVelvetFactory4());
\r
48 int deviceCount = 0;
\r
49 pSDK->device_enumerate(deviceCount);
\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
64 BlueFishFrameConsumerPtr card(new BlueFishVideoConsumer(format_desc));
\r
65 if(card != 0 && card->SetupDevice(deviceIndex) == false)
\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
75 frameBuffer_.set_capacity(1);
\r
76 thread_ = boost::thread([=]{Run();});
\r
79 ////////////////////////////////////////
\r
80 // BlueFishVideoConsumer destructor
\r
81 BlueFishVideoConsumer::~BlueFishVideoConsumer()
\r
83 frameBuffer_.push(nullptr),
\r
88 /*******************/
\r
90 /*******************/
\r
92 unsigned long BlueFishVideoConsumer::VidFmtFromFrameFormat(frame_format fmt)
\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
114 TCHAR* GetBluefishCardDesc(int cardType)
\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
155 bool BlueFishVideoConsumer::SetupDevice(unsigned int deviceIndex)
\r
157 return this->DoSetupDevice(deviceIndex);
\r
161 // Original initialization code
\r
162 bool BlueFishVideoConsumer::DoSetupDevice(unsigned int deviceIndex, std::wstring strDesiredFrameFormat)
\r
164 _deviceIndex = deviceIndex;
\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
170 int bufferIndex=0; //Bufferindex used when initializing the buffers
\r
172 if(strDesiredFrameFormat.size() == 0)
\r
173 strDesiredFrameFormat = TEXT("PAL");
\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
183 if(BLUE_FAIL(pSDK_->device_attach(_deviceIndex, FALSE))) {
\r
184 LOG << TEXT("BLUECARD ERROR: Failed to attach device") << _deviceIndex;
\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
198 if(vidFmt == VID_FMT_PAL) {
\r
199 strDesiredFrameFormat = TEXT("PAL");
\r
200 currentFormat_ = FFormatPAL;
\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
208 LOG << TEXT("BLUECARD INFO: Successfully configured bluecard for ") << strDesiredFrameFormat << TEXT(". (device ") << _deviceIndex << TEXT(")");
\r
210 if (pSDK_->has_output_key()) {
\r
212 int v4444 = FALSE, invert = FALSE, white = FALSE;
\r
213 pSDK_->set_output_key(iDummy, v4444, invert, white);
\r
216 if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) {
\r
217 pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI);
\r
222 pSDK_->set_vertical_flip(iDummy);
\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
229 LOG << TEXT("BLUECARD ERROR: Failed to get framestore parameters (device ") << _deviceIndex << TEXT(")");
\r
232 pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, m_golden));
\r
235 pSDK_->set_output_video(iDummy);
\r
237 // Now specify video output buffer
\r
238 pSDK_->render_buffer_update(0);
\r
240 pPlaybackControl_.reset(new FramePlaybackControl(FramePlaybackStrategyPtr(new BluefishPlaybackStrategy(this))));
\r
241 pPlaybackControl_->Start();
\r
243 LOG << TEXT("BLUECARD INFO: Successfully initialized device ") << _deviceIndex;
\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
252 _deviceIndex = deviceIndex;
\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
258 int bufferIndex=0; //Bufferindex used when initializing the buffers
\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
265 int videoCardType = pSDK_->has_video_cardtype();
\r
266 CASPAR_LOG(info) << "BLUECARD INFO: Card type: " << GetBluefishCardDesc(videoCardType) << TEXT(". (device ") << _deviceIndex << TEXT(")");
\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
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
285 if(vidFmt != desiredVideoFormat) {
\r
286 CASPAR_LOG(error) << "BLUECARD ERROR: Failed to set desired videomode: " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")");
\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
294 DisableVideoOutput();
\r
299 //Enable dual link output
\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
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
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
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
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
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
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
344 value.ulVal = MATRIX_709_CGR;
\r
345 if(vidFmt == VID_FMT_PAL) {
\r
346 value.ulVal = MATRIX_601_CGR;
\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
353 //Disable embedded audio
\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
359 CASPAR_LOG(info) << "BLUECARD INFO: Enabled embedded audio. (device " << _deviceIndex << TEXT(")");
\r
360 hasEmbeddedAudio_ = true;
\r
363 CASPAR_LOG(info) << "BLUECARD INFO: Successfully configured bluecard for " << format_desc_.name << TEXT(". (device ") << _deviceIndex << TEXT(")");
\r
365 if (pSDK_->has_output_key()) {
\r
367 int v4444 = FALSE, invert = FALSE, white = FALSE;
\r
368 pSDK_->set_output_key(iDummy, v4444, invert, white);
\r
371 if(pSDK_->GetHDCardType(_deviceIndex) != CRD_HD_INVALID) {
\r
372 pSDK_->Set_DownConverterSignalType((vidFmt == VID_FMT_PAL) ? SD_SDI : HD_SDI);
\r
375 ULONG videoGolden = BlueVelvetGolden(vidFmt, memFmt, updFmt);
\r
377 pFrameManager_ = BluefishFrameManagerPtr(new BluefishFrameManager(pSDK_, currentFormat_, videoGolden));
\r
379 pPlayback_ = std::make_shared<BluefishPlaybackStrategy>(this);
\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
386 EnableVideoOutput();
\r
388 CASPAR_LOG(info) << "BLUECARD INFO: Successfully initialized device " << _deviceIndex;
\r
392 bool BlueFishVideoConsumer::ReleaseDevice()
\r
394 pPlayback_.reset();
\r
396 pFrameManager_.reset();
\r
397 DisableVideoOutput();
\r
400 pSDK_->device_detach();
\r
403 CASPAR_LOG(info) << "BLUECARD INFO: Successfully released device " << _deviceIndex;
\r
407 void BlueFishVideoConsumer::EnableVideoOutput()
\r
409 //Need sync. protection?
\r
415 //Deactivate channel
\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
423 void BlueFishVideoConsumer::DisableVideoOutput()
\r
425 //Need sync. protection?
\r
431 //Deactivate channel
\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
439 void BlueFishVideoConsumer::display(const gpu_frame_ptr& frame)
\r
441 if(frame == nullptr)
\r
444 if(pException_ != nullptr)
\r
445 std::rethrow_exception(pException_);
\r
447 frameBuffer_.push(frame);
\r
450 void BlueFishVideoConsumer::Run()
\r
456 gpu_frame_ptr frame;
\r
457 frameBuffer_.pop(frame);
\r
458 if(frame == nullptr)
\r
461 pPlayback_->display(frame);
\r
465 pException_ = std::current_exception();
\r