UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
bluefish444.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2015-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif // HAVE_CONFIG_H
43
44#include <iomanip>
45#include <iostream>
46#include <queue>
47
48#include "bluefish444_common.h"
49
50#include "audio/types.h"
51#include "audio/utils.h"
52#include "debug.h"
53#include "host.h"
54#include "lib_common.h"
55#include "tv.h"
56#include "video.h"
57#include "video_capture.h"
58
59#ifndef UINT
60#define UINT uint32_t
61#endif
62
63#define BUFFERS 4
64
65#define MAX_BLUE_IN_CHANNELS 4
66
67using namespace std;
68
70
71/* prototypes of functions defined in this module */
72static void *worker(void *arg);
73static void show_help(void);
75static void SyncForSignal(struct vidcap_bluefish444_state *s);
76#ifdef _WIN32
77static int CompleteBlueAsyncReq(HANDLE hDevice, LPOVERLAPPED pOverlap);
78#endif
79static bool should_exit_worker = false;
80
81static void show_help()
82{
83 BLUE_S32 iDevices;
84 BLUEVELVETC_HANDLE pSDK = bfcFactory();
85 bfcEnumerate(pSDK, &iDevices);
86 bfcDestroy(pSDK);
87
88 printf("Bluefish444 capture\n");
89 printf("Usage\n");
90 printf("\t-t bluefish444[:framestore|:duplex][:depth={10|8}]"
91 "[:subfield][:4K][:device=<device_id>]\n");
92
93 printf("\t\t4K - use 4 inputs of a SuperNova card\n");
94
95 printf("\t\t<device_id> - ID of the Bluefish device (if more present)\n");
96 cout << "\t\t" << iDevices << " Bluefish devices found in this system" << endl;
97 if(iDevices == 1) {
98 cout << " (default)" << endl;
99 } else if(iDevices > 1) {
100 cout << ", valid indices [1," << iDevices << "]" << endl;
101 cout << "default is 1" << endl;
102 }
103}
104
106 virtual ~av_frame_base() {}
107};
108
110};
111
112struct av_frame : public av_frame_base {
113 av_frame(struct video_desc desc, int GoldenSize, int BytesPerFrame, int AudioLen) :
114 valid(true),
115 audio_len(0),
116 mGoldenSize(GoldenSize)
117 {
119 for(unsigned int i = 0; i < desc.tile_count; ++i) {
120 video->tiles[i].data_len = BytesPerFrame;
121 video->tiles[i].data = (char*)
122 bfAlloc(GoldenSize);
123 }
124 if(AudioLen) {
125 audio_data = (char *) bfAlloc(AudioLen);
126 } else {
127 audio_data = NULL;
128 }
129 }
130
132 bfFree(audio_len, audio_data);
133 for(unsigned int i = 0; i < video->tile_count; ++i) {
134 bfFree(mGoldenSize, video->tiles[i].data);
135 }
136 vf_free(video);
137 }
138
141 bool valid;
144};
145
147 BLUEVELVETC_HANDLE pSDK[MAX_BLUE_IN_CHANNELS];
149
151 struct timeval t0;
152
153 bool is4K;
156
157 unsigned long int LastFieldCount;
160
161 uint32_t VideoEngine;
162 uint32_t MemoryFormat;
163 uint32_t UpdateFormat;
165#ifdef _WIN32
166 blue_video_sync_struct *pIrqInfo;
167#endif
168
169#ifdef HAVE_BLUE_AUDIO
170 struct hanc_decode_struct objHancDecode;
171#endif
174 unsigned int *hanc_buffer;
175
176#ifdef _WIN32
177 OVERLAPPED OverlapChA;
178#endif
179
182
183 struct av_frame_base *CapturedFrame; // ready to send
184 struct av_frame *NetworkFrame; // frame that is being sent
185 queue<struct av_frame*> FreeFrameQueue;
186
187 pthread_mutex_t lock;
188 pthread_cond_t CapturedFrameReadyCV;
189 pthread_cond_t CapturedFrameDoneCV;
191
192 pthread_t worker_id;
193};
194
195static void BailOut(BLUEVELVETC_HANDLE pSDK);
196static void InitInputChannel(BLUEVELVETC_HANDLE pSDK, uint32_t DefaultInputChannel,
197 uint32_t UpdateFormat, uint32_t MemoryFormat, uint32_t VideoEngine);
198void RouteChannel(BLUEVELVETC_HANDLE pSDK, uint32_t Source, uint32_t Destination,
199 uint32_t LinkType);
200bool UpdateVideoMode(struct vidcap_bluefish444_state *s, uint32_t VideoMode);
201#ifdef HAVE_BLUE_AUDIO
202static bool setup_audio(struct vidcap_bluefish444_state *s, unsigned int flags);
203#endif
204
205static void BailOut(BLUEVELVETC_HANDLE pSDK)
206{
207 bfcDetach(pSDK);
208 bfcDestroy(pSDK);
209}
210
211void InitInputChannel(BLUEVELVETC_HANDLE pSDK, uint32_t DefaultInputChannel, uint32_t UpdateFormat, uint32_t MemoryFormat, uint32_t VideoEngine)
212{
213 //MOST IMPORTANT: as the first step set the channel that we want to work with
214 bfcSetCardProperty32(pSDK, DEFAULT_VIDEO_INPUT_CHANNEL, DefaultInputChannel);
215
216 //make sure the FIFO hasn't been left running (e.g. application crash before), otherwise we can't change card properties
217 bfcVideoCaptureStop(pSDK);
218
219 bfcSetCardProperty32(pSDK, VIDEO_INPUT_UPDATE_TYPE, UpdateFormat);
220
221 bfcSetCardProperty32(pSDK, VIDEO_INPUT_MEMORY_FORMAT, MemoryFormat);
222
223 //Only set the Video Engine after setting up the required update type and memory format and make sure that there is a valid input signal
224 bfcSetCardProperty32(pSDK, VIDEO_INPUT_ENGINE, VideoEngine);
225}
226
227void RouteChannel(BLUEVELVETC_HANDLE pSDK, uint32_t Source, uint32_t Destination, uint32_t LinkType)
228{
229 uint32_t val = EPOCH_SET_ROUTING(Source, Destination, LinkType);
230 bfcSetCardProperty32(pSDK, MR2_ROUTING, val);
231}
232
233bool UpdateVideoMode(struct vidcap_bluefish444_state *s, uint32_t VideoMode)
234{
235 for (int i = 0; i < bluefish_frame_modes_count; ++i) {
236 if(bluefish_frame_modes[i].mode == VideoMode) {
240 s->interlaced = true;
241 } else {
242 s->interlaced = false;
243 }
244
245 s->video_desc.fps =
247 s->video_desc.width =
249 s->video_desc.height =
251
252 streamsize ss = cout.precision();
253 cout << "[Blue cap] Format changed " <<
254 bluefish_frame_modes[i].width << "x" <<
257 " @" << setprecision(2) <<
258 bluefish_frame_modes[i].fps << setprecision(ss) << endl;
259 return true;
260 }
261 }
262 return false;
263}
264
265#ifdef _WIN32
266static int CompleteBlueAsyncReq(HANDLE hDevice, LPOVERLAPPED pOverlap)
267{
268 DWORD bytesReturned;
269 ResetEvent(pOverlap->hEvent);
270 GetOverlappedResult(hDevice, pOverlap, &bytesReturned, TRUE);
271 //cout << "Bytes ret: " << bytesReturned << endl;
272 return bytesReturned;
273}
274#endif
275
277{
278#ifdef _WIN32
279 assert(s->attachedDevices == 1);
280
281 BOOL bWaitForField = TRUE;
282
283 //We need to wait for a major interrupt (sub field interrupt == 0) before we schedule a frame to be captured
284 UINT SubFieldIrqs = 0;
285 UINT VideoMsc = 0;
286 DWORD IrqReturn = 0;
287 do
288 {
289 bfcVideoSyncStructSet(s->pSDK[0], s->pIrqInfo, BLUE_VIDEO_INPUT_CHANNEL_A,
290 s->UpdateFormat,
291 IGNORE_SYNC_WAIT_TIMEOUT_VALUE);
292 bfcWaitVideoSyncAsync(s->pSDK[0], &s->OverlapChA, s->pIrqInfo);
293 IrqReturn = WaitForSingleObject(s->OverlapChA.hEvent, 1000);
294 CompleteBlueAsyncReq(bfcGetHandle(s->pSDK[0]), &s->OverlapChA);
295
296 bfcVideoSyncStructGet(s->pSDK[0], s->pIrqInfo, VideoMsc, SubFieldIrqs);
297 if(s->video_desc.interlacing == PROGRESSIVE || (VideoMsc & 0x1))
298 bWaitForField = FALSE;
299
300 }while(!((SubFieldIrqs == 0) && !bWaitForField)); //we need to schedule the field capture when SubFieldIrqs is 0
301#else
302 UNUSED(s);
303#endif
304}
305
307{
308 unsigned long int FieldCount = 0;
309
310 if(s->VideoEngine == VIDEO_ENGINE_FRAMESTORE) {
311 s->ScheduleID = s->CapturingID = s->DoneID = 0;
312
313 if(s->SubField) {
315 }
316
317 //start the capture sequence
318 // all input channels must be genlocked
319 bfcWaitVideoInputSync(s->pSDK[0], s->UpdateFormat, &FieldCount); //this call just synchronises us to the card
320 for(int i = 0; i < s->attachedDevices; ++i) {
321 bfcRenderBufferCapture(s->pSDK[i], BlueBuffer_Image_HANC(s->ScheduleID));
322 }
323 s->CapturingID = s->ScheduleID;
324 s->ScheduleID = (s->ScheduleID + 1) % BUFFERS;
325 s->LastFieldCount = FieldCount;
326
327 if(s->SubField) {
329 }
330
331 bfcWaitVideoInputSync(s->pSDK[0], s->UpdateFormat, &FieldCount); //the first buffer starts to be captured now; this is it's field count
332 for(int i = 0; i < s->attachedDevices; ++i) {
333 bfcRenderBufferCapture(s->pSDK[i], BlueBuffer_Image_HANC(s->ScheduleID));
334 }
335 s->DoneID = s->CapturingID;
336 s->CapturingID = s->ScheduleID;
337 s->ScheduleID = (s->ScheduleID + 1) % BUFFERS;
338 s->LastFieldCount = FieldCount;
339 } else {
340 for(int i = 0; i < s->attachedDevices; ++i) {
341 bfcWaitVideoInputSync(s->pSDK[i], s->UpdateFormat, &FieldCount);
342 }
343 s->LastFieldCount = FieldCount;
344 }
345}
346
347static void vidcap_bluefish444_probe(device_info **available_cards, int *count, void (**deleter)(void *))
348{
349 *deleter = free;
350
351 BLUE_S32 iDevices;
352 BLUEVELVETC_HANDLE pSDK = bfcFactory();
353 bfcEnumerate(pSDK, &iDevices);
354 bfcDestroy(pSDK);
355
356 *count = iDevices;
357 *available_cards = (struct device_info *) calloc(iDevices, sizeof(struct device_info));
358 for (int i = 0; i < iDevices; ++i) {
359 auto& card = (*available_cards)[i];
360 snprintf(card.dev, sizeof(card.dev), ":device=%d", i + 1);
361 snprintf(card.name, sizeof(card.name), "Bluefish444 card #%d", i);
362 }
363}
364
365#ifdef HAVE_BLUE_AUDIO
366static bool setup_audio(struct vidcap_bluefish444_state *s, unsigned int flags)
367{
368 memset(&s->objHancDecode, 0, sizeof(s->objHancDecode));
369
371 s->objHancDecode.audio_ch_required_mask = 0;
372 /* MONO_CHANNEL_9 and _10 are used for analog output */
373 switch (s->audio.ch_count) {
374 case 16:
375 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_18;
376 // fall through
377 case 15:
378 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_17;
379 // fall through
380 case 14:
381 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_16;
382 // fall through
383 case 13:
384 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_15;
385 // fall through
386 case 12:
387 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_14;
388 // fall through
389 case 11:
390 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_13;
391 // fall through
392 case 10:
393 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_12;
394 // fall through
395 case 9:
396 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_11;
397 // fall through
398 case 8:
399 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_8;
400 // fall through
401 case 7:
402 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_7;
403 // fall through
404 case 6:
405 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_6;
406 // fall through
407 case 5:
408 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_5;
409 // fall through
410 case 4:
411 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_4;
412 // fall through
413 case 3:
414 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_3;
415 // fall through
416 case 2:
417 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_2;
418 // fall through
419 case 1:
420 s->objHancDecode.audio_ch_required_mask |= MONO_CHANNEL_1;
421 break;
422 default:
423 cerr << "Too many output channels requested." << endl;
424 return false;
425 }
426 s->objHancDecode.type_of_sample_required = (AUDIO_CHANNEL_16BIT|AUDIO_CHANNEL_LITTLEENDIAN);
427 s->objHancDecode.max_expected_audio_sample_count = 2002; // 1 frame time for 23.98 FPS
429 s->objHancDecode.audio_input_source = AUDIO_INPUT_SOURCE_EMB;
430 } else if(flags & VIDCAP_FLAG_AUDIO_AESEBU) {
431 s->objHancDecode.audio_input_source = AUDIO_INPUT_SOURCE_AES;
432 } else { // flags == VIDCAP_FLAG_AUDIO_ANALOG
433 cerr << "[Blue cap] Analog audio not supported." << endl;
434 return false;
435 }
436
437 s->audio.bps = 2;
438 s->audio.sample_rate = 48000; // perhaps the driver does not support different
439 s->audio.max_size = 4*4096*16;
440
441 LOG(LOG_LEVEL_NOTICE) << "[Blue cap] audio initialized sucessfully: " << audio_desc_from_frame(&s->audio) << "\n";
442
443 s->hanc_buffer = (unsigned int *) bfAlloc(MAX_HANC_SIZE);
444
445 return true;
446}
447#endif
448
450 pthread_mutex_lock(&s->lock);
451 if(!s->CapturedFrame) {
453 pthread_cond_signal(&s->CapturedFrameReadyCV);
454 }
455 pthread_mutex_unlock(&s->lock);
456}
457
458static void *worker(void *arg)
459{
460 struct vidcap_bluefish444_state *s =
461 (struct vidcap_bluefish444_state *) arg;
462 uint32_t GoldenSize = 0;
463 uint32_t ChunkSize = 0;
464 uint32_t nChunks = 1;
465 unsigned long int FieldCount = 0;
466
467 while(!should_exit_worker) {
468 BLUE_U32 val32;
469 UINT SubFieldIrqs = 0;
470 uint32_t VideoMode = VID_FMT_INVALID;
471 int BufferId = -1;
472 int hanc_buffer_id=-1; // flags required for starting audio capture
473
474 blue_videoframe_info_ex FrameInfo;
475
476 unsigned long int CurrentFieldCount = FieldCount;
477 struct av_frame *current_frame = NULL;
478 int nOffset = 0;
479
480 // Synchronize
481 if(!s->SubField || s->SavedVideoMode == VID_FMT_INVALID) {
482 //Check if we have a valid input signal, all cards should be in sync
483 bfcWaitVideoInputSync(s->pSDK[0], s->UpdateFormat, &FieldCount); //synchronise with the card before querying VIDEO_INPUT_SIGNAL_VIDEO_MODE
484
485 for(int i = 0; i < s->attachedDevices; ++i) {
486 bfcQueryCardProperty32(s->pSDK[i], VIDEO_INPUT_SIGNAL_VIDEO_MODE, &val32);
487 if(val32 >= VID_FMT_INVALID)
488 {
489 cerr << "No valid input signal on channel " <<
490 (char)('A' + i) << endl;
491 signal_error(s);
492 goto next_iteration;
493 }
494 if(i == 0) {
495 VideoMode = val32;
496 } else {
497 if(val32 != VideoMode) {
498 cerr << "Different signal detected on channel " <<
499 (char)('A' + i) << " than on " <<
500 "channel A" << endl;
501 signal_error(s);
502 goto next_iteration;
503 }
504 }
505 }
506
507 } else {
508#ifdef _WIN32
509 DWORD IrqReturn = 0;
510 UINT VideoMsc = 0;
511 // we do not allow mode change when in subfield mode
512 VideoMode = s->SavedVideoMode;
513
514 bfcVideoSyncStructSet(s->pSDK[0], s->pIrqInfo, BLUE_VIDEO_INPUT_CHANNEL_A,
515 s->UpdateFormat,
516 IGNORE_SYNC_WAIT_TIMEOUT_VALUE);
517 bfcWaitVideoSyncAsync(s->pSDK[0], &s->OverlapChA, s->pIrqInfo);
518 IrqReturn = WaitForSingleObject(s->OverlapChA.hEvent, 1000);
519 CompleteBlueAsyncReq(bfcGetHandle(s->pSDK[0]), &s->OverlapChA);
520
521 bfcVideoSyncStructGet(s->pSDK[0], s->pIrqInfo, VideoMsc, SubFieldIrqs);
522 //cerr <<FieldCount <<" " << SubFieldIrqs <<endl;
523 if(SubFieldIrqs == 0) {
524 FieldCount = VideoMsc;
525 }
526#endif
527 }
528
529 if(s->LastFieldCount + 2 < FieldCount)
530 {
531 cout << "Error: dropped " << ((FieldCount - s->LastFieldCount + 2)/2) << " frames" << endl;
532 }
533
534 // check for mode change
535 if(s->SavedVideoMode != VideoMode) {
536 if(UpdateVideoMode(s, VideoMode)) {
537 // mode changed
538 pthread_mutex_lock(&s->lock);
539 if(s->NetworkFrame) {
540 s->NetworkFrame->valid = false;
541 }
542 while(s->CapturedFrame) {
543 pthread_cond_wait(&s->CapturedFrameDoneCV, &s->lock);
544 }
545 while(!s->FreeFrameQueue.empty()) {
546 struct av_frame *frame = s->FreeFrameQueue.front();
547 s->FreeFrameQueue.pop();
548 delete frame;
549 }
550
551 s->SavedVideoMode = VideoMode;
552
553 uint32_t val32 = 0; // no subfield interrupts
554 if(s->SubField) {
555 if(s->interlaced) {
556 s->UpdateFormat = UPD_FMT_FIELD;
557 val32 = 2;
558 } else { // progressive
559 if(s->video_desc.fps > 25) {
560 val32 = 2;
561 } else {
562 val32 = 4;
563 }
564 }
565 }
566
567 BLUE_U32 Width, Height, BytesPerLine, BytesPerFrame;
568 bfcGetVideoInfo(VideoMode, s->UpdateFormat, s->MemoryFormat, &Width, &Height, &BytesPerLine, &BytesPerFrame, &GoldenSize);
569 ChunkSize = BytesPerFrame;
570 nChunks = 1;
571
572 for(int i = 0; i < 2; ++i) {
573 s->FreeFrameQueue.push(new av_frame(s->video_desc, GoldenSize, BytesPerFrame,
574 s->audio.max_size));
575 }
576 pthread_mutex_unlock(&s->lock);
577
578 for(int i = 0; i < s->attachedDevices; ++i) {
579 bfcSetCardProperty32(s->pSDK[i], VIDEO_INPUT_UPDATE_TYPE,
580 s->UpdateFormat);
581 bfcSetCardProperty32(s->pSDK[i], EPOCH_SUBFIELD_INPUT_INTERRUPTS,
582 val32);
583 }
584 if(val32) {
585 ChunkSize /= val32;
586 nChunks = val32;
587 } else {
588 ChunkSize = GoldenSize;
589 }
590 cout << "Golden : " << GoldenSize << endl <<
591 "BytesPerFrame: " << BytesPerFrame << endl <<
592 "ChunkSize : " << ChunkSize << endl;
593
594 } else {
595 cerr << "[Blue422 cap] Fatal: unknown video mode: " << VideoMode << endl;
596 signal_error(s);
597 goto next_iteration;
598 }
599 SyncForSignal(s);
600 }
601
602 pthread_mutex_lock(&s->lock);
603 while(s->FreeFrameQueue.empty()) {
604 pthread_cond_wait(&s->FreeFrameQueueNotEmptyCV, &s->lock);
605 }
606 current_frame = s->FreeFrameQueue.front();
607 s->FreeFrameQueue.pop();
608 pthread_mutex_unlock(&s->lock);
609
610 if(s->VideoEngine == VIDEO_ENGINE_DUPLEX) {
611#ifdef _WIN32
612 unsigned int FifoSize = 0;
613 if(BLUE_FAIL(bfcGetCaptureVideoFrameInfoEx(s->pSDK[0], &s->OverlapChA, FrameInfo,
614 0, &FifoSize))) {
615 cerr << "Capture frame failed!" << endl;
616 signal_error(s);
617 goto next_iteration;
618 }
619#else
620 if(BLUE_FAIL(bfcGetCaptureVideoFrameInfoEx(s->pSDK[0], &FrameInfo))) {
621 cerr << "Capture frame failed!" << endl;
622 signal_error(s);
623 goto next_iteration;
624 }
625#endif
626
627 if(FrameInfo.nVideoSignalType >= s->InvalidVideoModeFlag) {
628 cerr << "Invalid video mode!" << endl;
629 signal_error(s);
630 goto next_iteration;
631 }
632
633 if(FrameInfo.BufferId == -1) {
634 cerr << "No buffer!" << endl;
635 signal_error(s);
636 goto next_iteration;
637 }
638 BufferId = FrameInfo.BufferId;
639 } else {
640 BufferId = s->DoneID;
641 }
642
643 if(s->SubField) {
644 if(SubFieldIrqs == 0) {
645 nOffset = (nChunks - 1) * ChunkSize;
646 current_frame->video->last_fragment = TRUE;
647 } else {
648 nOffset = (SubFieldIrqs - 1) * ChunkSize;
649 current_frame->video->last_fragment = FALSE;
650 }
651 current_frame->video->tiles[0].data_len = ChunkSize;
652 current_frame->video->fragment = TRUE;
653 current_frame->video->tiles[0].offset = nOffset;
654 current_frame->video->frame_fragment_id = CurrentFieldCount & 0x3fff;
655 }
656
657 //DMA the frame from the card to our buffer
658 for(int i = 0; i < s->attachedDevices; ++i) {
659#ifdef _WIN32
660 bfcSystemBufferReadAsync(s->pSDK[i], (unsigned char *)
661 current_frame->video->tiles[i].data,
662 ChunkSize, NULL,
663 BlueImage_HANC_DMABuffer(BufferId, BLUE_DATA_IMAGE), nOffset);
664#else
665 bfcSystemBufferRead(s->pSDK[i], (unsigned char *)
666 current_frame->video->tiles[i].data,
667 ChunkSize,
668 BlueImage_HANC_DMABuffer(BufferId, BLUE_DATA_IMAGE), nOffset);
669#endif
670 }
671
672#ifdef HAVE_BLUE_AUDIO
673 if(s->UpdateFormat == UPD_FMT_FRAME) {
674 hanc_buffer_id = BufferId;
675 }
676
677 if(s->grab_audio && hanc_buffer_id != -1) {
678#ifdef _WIN32
679 bfcSystemBufferReadAsync(s->pSDK[0], (unsigned char *) s->hanc_buffer, MAX_HANC_SIZE, NULL, BlueImage_HANC_DMABuffer(BufferId, BLUE_DATA_HANC));
680#else
681 bfcSystemBufferRead(s->pSDK[0], (unsigned char *) s->hanc_buffer, MAX_HANC_SIZE, BlueImage_HANC_DMABuffer(BufferId, BLUE_DATA_HANC), 0);
682#endif
683 s->objHancDecode.audio_pcm_data_ptr = current_frame->audio_data;
684 int iCardType = CRD_INVALID;
685 bfcQueryCardType(s->pSDK[0], &iCardType, s->iDeviceId);
686 bfcDecodeHancFrameEx(s->pSDK[0], iCardType, (unsigned int *) s->hanc_buffer,
687 &s->objHancDecode);
688 current_frame->audio_len = s->objHancDecode.no_audio_samples *
689 s->audio.bps;
690 }
691#endif
692
693
694 if(s->VideoEngine == VIDEO_ENGINE_FRAMESTORE) {
695 if(!s->SubField || SubFieldIrqs == 0) {
696 //tell the card to capture another frame at the next interrupt
697 for(int i = 0; i < s->attachedDevices; ++i) {
698 bfcRenderBufferCapture(s->pSDK[i],
699 BlueBuffer_Image_HANC(s->ScheduleID));
700 }
701
702 s->DoneID = s->CapturingID;
703 s->CapturingID = s->ScheduleID;
704 s->ScheduleID = (s->ScheduleID + 1) % BUFFERS;
705 }
706 }
707
708 s->LastFieldCount = FieldCount;
709 if(!s->SubField || SubFieldIrqs == 0) {
710 s->frames++;
711
712 struct timeval t;
713 gettimeofday(&t, NULL);
714 double seconds = tv_diff(t, s->t0);
715 if (seconds >= 5) {
716 float fps = s->frames / seconds;
717 log_msg(LOG_LEVEL_INFO, "[Blue cap] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps);
718 s->t0 = t;
719 s->frames = 0;
720 }
721 }
722
723 pthread_mutex_lock(&s->lock);
724 while(s->CapturedFrame) {
725 pthread_cond_wait(&s->CapturedFrameDoneCV, &s->lock);
726 }
727 s->CapturedFrame = current_frame;
728 pthread_cond_signal(&s->CapturedFrameReadyCV);
729 pthread_mutex_unlock(&s->lock);
730
731next_iteration:
732 ;
733 }
734
735 return NULL;
736}
737
738static void parse_fmt(struct vidcap_bluefish444_state *s, char *fmt) {
739 char *item,
740 *save_ptr = NULL;
741 if(!fmt) {
742 return;
743 }
744 while((item = strtok_r(fmt, ":", &save_ptr))) {
745 if(strcasecmp(item, "framestore") == 0) {
746 s->VideoEngine = VIDEO_ENGINE_FRAMESTORE;
747 } else if(strcasecmp(item, "duplex") == 0) {
748 s->VideoEngine = VIDEO_ENGINE_DUPLEX;
749 } else if(strncasecmp(item, "depth=", strlen("depth=")) == 0) {
750 int depth = atoi(item + strlen("depth="));
751 if(depth == 8) {
752 s->MemoryFormat = MEM_FMT_2VUY;
753 } else if (depth == 10) {
754 s->MemoryFormat = MEM_FMT_V210;
755 } else {
756 cerr << "[Blue cap] Unsupported bit depth: " << depth << endl;
757 }
758 } else if(strcasecmp(item, "subfield") == 0) {
759 s->SubField = true;
760 } else if(strncasecmp(item, "device=", strlen("device=")) == 0) {
761 s->iDeviceId = atoi(item + strlen("device="));
762 } else if(strcasecmp(item, "4K") == 0) {
763 s->is4K = true;
764 } else {
765 cerr << "[Blue cap] Unrecognized option: " << item << endl;
766 }
767
768 fmt = NULL;
769 }
770}
771
772static int
774{
775 struct vidcap_bluefish444_state *s;
776 ULONG InputChannels[4] = {
777 BLUE_VIDEO_INPUT_CHANNEL_A,
778 BLUE_VIDEO_INPUT_CHANNEL_B,
779 BLUE_VIDEO_INPUT_CHANNEL_C,
780 BLUE_VIDEO_INPUT_CHANNEL_D
781 };
782 ULONG Sources[4] = { EPOCH_SRC_SDI_INPUT_A,
783 EPOCH_SRC_SDI_INPUT_B,
784 EPOCH_SRC_SDI_INPUT_C,
785 EPOCH_SRC_SDI_INPUT_D
786 };
787 ULONG Destinations[4] = { EPOCH_DEST_INPUT_MEM_INTERFACE_CHA,
788 EPOCH_DEST_INPUT_MEM_INTERFACE_CHB,
789 EPOCH_DEST_INPUT_MEM_INTERFACE_CHC,
790 EPOCH_DEST_INPUT_MEM_INTERFACE_CHD
791 };
792
793 if(vidcap_params_get_fmt(params) && strcmp(vidcap_params_get_fmt(params), "help") == 0) {
794 show_help();
795 return VIDCAP_INIT_NOERR;
796 }
797
798 printf("vidcap_bluefish444_init\n");
799
801
802 if(s == NULL) {
803 printf("Unable to allocate bluefish444 capture state\n");
804 return VIDCAP_INIT_FAIL;
805 }
806
807 s->MemoryFormat = MEM_FMT_2VUY;
808 s->VideoEngine = VIDEO_ENGINE_DUPLEX;
809 s->UpdateFormat = UPD_FMT_FRAME;
810 s->SubField = false;
811 s->iDeviceId = 1;
812 s->is4K = false;
813
814 char *tmp_fmt = strdup(vidcap_params_get_fmt(params));
815 parse_fmt(s, tmp_fmt);
816 free(tmp_fmt);
817
818#ifdef _WIN32
819 memset(&s->OverlapChA, 0, sizeof(s->OverlapChA));
820 s->OverlapChA.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
821#endif
822
823 int iDevices = 0;
824 s->SavedVideoMode = VID_FMT_INVALID;
825
826 if(s->SubField) {
827#ifdef _WIN32
828 s->VideoEngine = VIDEO_ENGINE_FRAMESTORE;
829 s->pIrqInfo = bfcNewVideoSyncStruct(s->pSDK);
830#else
831 cerr << "Subfields not supported under Linux." << endl;
832 goto error;
833#endif
834 }
835
836 if(s->is4K) {
837 s->VideoEngine = VIDEO_ENGINE_FRAMESTORE;
838 s->attachedDevices = 4;
839 s->video_desc.tile_count = 4;
840 if(s->VideoEngine == VIDEO_ENGINE_DUPLEX) {
841 cerr << "4K mode is not supported in duplex mode." << endl;
842 goto error;
843 }
844 if(s->SubField) {
845 cerr << "Subfields are not supported in 4K mode." << endl;
846 goto error;
847 }
848 } else {
849 s->attachedDevices = 1;
850 }
851
852 for(int i = 0; i < s->attachedDevices; ++i) {
853 s->pSDK[i] = bfcFactory();
854 }
855
856 bfcEnumerate(s->pSDK[0], &iDevices);
857 if(iDevices < 1) {
858 cout << "No Bluefish device detected." << endl;
859 goto error;
860 }
861
862 for(int i = 0; i < s->attachedDevices; ++i) {
863 if(BLUE_FAIL(bfcAttach(s->pSDK[i], s->iDeviceId))) {
864 cerr << "Error on device attach (channel " <<
865 (char)('A' + i) << ")" << endl;
866 goto error;
867 }
868 }
869
870 if(s->is4K) {
871 BLUE_U32 firmware;
872 int iCardType = CRD_INVALID;
873 bfcQueryCardType(s->pSDK[0], &iCardType, s->iDeviceId);
874 bfcQueryCardProperty32(s->pSDK[0], EPOCH_GET_PRODUCT_ID, &firmware);
875
876 if (iCardType != CRD_BLUE_SUPER_NOVA) {
877 cerr << "4K supported only for a SuperNova card!" << endl;
878 goto error;
879 }
880 if(firmware != ORAC_4SDIINPUT_FIRMWARE_PRODUCTID) {
881 cerr << "Wrong firmware; need 4 input channels (QuadIn)";
882 goto error;
883 }
884 }
885
886 for(int i = 0; i < s->attachedDevices; ++i) {
887 InitInputChannel(s->pSDK[i], InputChannels[i], s->UpdateFormat, s->MemoryFormat, s->VideoEngine);
888 RouteChannel(s->pSDK[i], Sources[i], Destinations[i], BLUE_CONNECTOR_PROP_SINGLE_LINK);
889 }
890
891 //Get VID_FMT_INVALID flag; this enum has changed over time and might be different depending on which driver this application runs on
892 BLUE_U32 val32;
893 bfcQueryCardProperty32(s->pSDK[0], INVALID_VIDEO_MODE_FLAG, &val32);
894 s->InvalidVideoModeFlag = val32;
895
896 s->LastFieldCount = 0;
897
898 s->frames = 0;
899 gettimeofday(&s->t0, NULL);
900
902 if(s->MemoryFormat == MEM_FMT_2VUY) {
904 } else { // MEM_FMT_V210
906 }
907
908 // make sure that capture is stopped
909 for(int i = 0; i < s->attachedDevices; ++i) {
910 bfcVideoCaptureStop(s->pSDK[i]);
911 if(BLUE_FAIL(bfcVideoCaptureStart(s->pSDK[i]))) {
912 /* is this really needed? Sometimes this command keeps failing but
913 * we can stil go on, so ignore this error */
914 //cerr << "Error video capture start failed on channel A" << endl;
915 //goto error;
916 }
917 }
918
919 gettimeofday(&s->t0, NULL);
920
921 s->grab_audio = false;
922 s->audio.data = NULL;
923 s->audio.max_size = 0;
924 s->hanc_buffer = NULL;
925#ifdef HAVE_BLUE_AUDIO
927 if(s->SubField) {
928 cerr << "[Blue cap] Unable to grab audio in sub-field mode." << endl;
929 goto error;
930 }
932 if(ret == false) {
933 cerr << "[Blue cap] Unable to setup audio." << endl;
934 goto error;
935 } else {
936 s->grab_audio = true;
937 }
938 }
939#else
941 cerr << "[Blue cap] Unable to capture audio. Support isn't compiled in." << endl;
942 goto error;
943 }
944#endif
945
946 pthread_mutex_init(&s->lock, NULL);
947 pthread_cond_init(&s->CapturedFrameReadyCV, NULL);
948 pthread_cond_init(&s->CapturedFrameDoneCV, NULL);
949 pthread_cond_init(&s->FreeFrameQueueNotEmptyCV, NULL);
950 s->NetworkFrame = NULL;
951 s->CapturedFrame = NULL;
952
953 if(pthread_create(&s->worker_id, NULL, worker, (void *) s) != 0) {
954 cerr << "[Blue cap] Error initializing thread." << endl;
955 goto error;
956 }
957
958 *state = s;
959 return VIDCAP_INIT_OK;
960
961error:
962 for(int i = 0; i < s->attachedDevices; ++i) {
963 BailOut(s->pSDK[i]);
964 }
965 delete s;
966 return VIDCAP_INIT_FAIL;
967}
968
970{
972
973 assert(s != NULL);
974
975 pthread_mutex_lock(&s->lock);
976 if(s->NetworkFrame) {
977 if(s->NetworkFrame->valid) {
978 s->FreeFrameQueue.push(s->NetworkFrame);
979 pthread_cond_signal(&s->FreeFrameQueueNotEmptyCV);
980 } else {
981 delete s->NetworkFrame;
982 }
983 s->NetworkFrame = NULL;
984 }
985 if(s->CapturedFrame) {
986 delete s->CapturedFrame;
987 s->CapturedFrame = NULL;
988 pthread_cond_signal(&s->CapturedFrameDoneCV);
989 }
990 should_exit_worker = true;
991 pthread_mutex_unlock(&s->lock);
992 pthread_join(s->worker_id, NULL);
993
994#ifdef _WIN32
995 CloseHandle(s->OverlapChA.hEvent);
996#endif
997
998 delete s->CapturedFrame;
999 delete s->NetworkFrame;
1000 while(!s->FreeFrameQueue.empty()) {
1001 delete s->FreeFrameQueue.front();
1002 s->FreeFrameQueue.pop();
1003 }
1004
1005 bfFree(MAX_HANC_SIZE, s->hanc_buffer);
1006
1007 for(int i = 0; i < s->attachedDevices; ++i) {
1008 bfcVideoCaptureStop(s->pSDK[i]);
1009 BailOut(s->pSDK[i]);
1010 }
1011
1012 pthread_cond_destroy(&s->CapturedFrameReadyCV);
1013 pthread_cond_destroy(&s->CapturedFrameDoneCV);
1014 pthread_cond_destroy(&s->FreeFrameQueueNotEmptyCV);
1015
1016 delete s;
1017}
1018
1019static struct video_frame *
1021{
1023
1024 struct av_frame *frame;
1025 struct video_frame *res = NULL;
1026
1027 *audio = NULL;
1028
1029 pthread_mutex_lock(&s->lock);
1030 if(s->NetworkFrame) {
1031 if(s->NetworkFrame->valid) {
1032 s->FreeFrameQueue.push(s->NetworkFrame);
1033 pthread_cond_signal(&s->FreeFrameQueueNotEmptyCV);
1034 } else {
1035 delete s->NetworkFrame;
1036 }
1037 s->NetworkFrame = NULL;
1038 }
1039
1040 while(!s->CapturedFrame) {
1041 pthread_cond_wait(&s->CapturedFrameReadyCV, &s->lock);
1042 }
1043
1044 if(dynamic_cast<av_frame_nosignal *>(s->CapturedFrame)) {
1045 delete s->CapturedFrame;
1046 s->CapturedFrame = NULL;
1047 pthread_cond_signal(&s->CapturedFrameDoneCV);
1048 pthread_mutex_unlock(&s->lock);
1049 return NULL;
1050 } else {
1051 frame = dynamic_cast<av_frame *>(s->CapturedFrame);
1052 }
1053
1054 if(frame->audio_len) {
1055 s->audio.data = frame->audio_data;
1056 s->audio.data_len = frame->audio_len;
1057 *audio = &s->audio;
1058 }
1059
1060 res = frame->video;
1061
1062 s->NetworkFrame = frame;
1063 s->CapturedFrame = NULL;
1064 pthread_cond_signal(&s->CapturedFrameDoneCV);
1065
1066 // Merge two fields together if needed (subfield, interlaced)
1067 if(res->fragment) {
1068 if(res->frame_fragment_id % 2 == 0) {
1069 //upper field
1070 res->last_fragment = FALSE;
1071 } else {
1072 //bottom field
1073 res->tiles[0].offset += res->tiles[0].data_len * 2;
1074 res->frame_fragment_id &= 0xfffffffeu;
1075 }
1076 if(s->interlaced) {
1078 }
1079 }
1080
1081 pthread_mutex_unlock(&s->lock);
1082
1083 return res;
1084}
1085
1093
1095
#define UNUSED(x)
void ** state
int void * val
struct video_desc desc
struct video_frame * frame
const char * fmt
const char unsigned int flags
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
This file contains definition of some common audio types.
#define MAX_HANC_SIZE
static const int bluefish_frame_modes_count
static const struct bluefish_frame_mode_t bluefish_frame_modes[]
#define TRUE
#define FALSE
u32 UINT
Definition cuda_dxt.cu:13
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG(level)
Definition debug.h:313
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_NO_GENERIC_FPS_INDICATOR
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
int count
Definition hd-rum.c:44
unsigned int audio_capture_channels
Definition host.cpp:163
#define DEFAULT_AUDIO_CAPTURE_CHANNELS
Definition host.h:89
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
enum openssl_mode mode
struct used to comunicate with audio capture/playback device
Definition types.h:99
int sample_rate
Definition types.h:101
char * data
Definition types.h:102
int ch_count
Definition types.h:104
int data_len
Definition types.h:103
int bps
Definition types.h:100
int max_size
Definition types.h:105
virtual ~av_frame_base()
struct video_frame * video
char * audio_data
av_frame(struct video_desc desc, int GoldenSize, int BytesPerFrame, int AudioLen)
enum interlacing_t interlacing
Definition hd-rum.c:27
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int offset
Fragment offset from tile beginning (in bytes). Used only if frame is fragmented.
Definition types.h:292
pthread_cond_t CapturedFrameReadyCV
pthread_cond_t CapturedFrameDoneCV
BLUEVELVETC_HANDLE pSDK[MAX_BLUE_IN_CHANNELS]
struct av_frame_base * CapturedFrame
pthread_cond_t FreeFrameQueueNotEmptyCV
struct av_frame * NetworkFrame
struct audio_frame audio
struct video_desc video_desc
queue< struct av_frame * > FreeFrameQueue
unsigned long int LastFieldCount
struct hanc_decode_struct objHancDecode
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
enum interlacing_t interlacing
Definition types.h:307
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
unsigned int tile_count
Definition types.h:344
unsigned int frame_fragment_id
Used only if (fragment == 1). ID of the frame. Fragments of same frame must have the same ID.
Definition types.h:319
unsigned int fragment
Indicates that the tile is fragmented. Normally not used (only for Bluefish444).
Definition types.h:315
unsigned int last_fragment
Used only if (fragment == 1). Indicates this is the last fragment.
Definition types.h:317
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
depth
Definition types.h:125
@ UPPER_FIELD_FIRST
First stored field is top, followed by bottom.
Definition types.h:165
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
Definition types.h:75
struct audio_desc audio_desc_from_frame(const struct audio_frame *frame)
Definition utils.cpp:196
This is an umbrella header for video functions.
static void WaitForMajorInterrupt(struct vidcap_bluefish444_state *s)
static void SyncForSignal(struct vidcap_bluefish444_state *s)
static void vidcap_bluefish444_probe(device_info **available_cards, int *count, void(**deleter)(void *))
static void * worker(void *arg)
static void BailOut(BLUEVELVETC_HANDLE pSDK)
static void InitInputChannel(BLUEVELVETC_HANDLE pSDK, uint32_t DefaultInputChannel, uint32_t UpdateFormat, uint32_t MemoryFormat, uint32_t VideoEngine)
static int vidcap_bluefish444_init(struct vidcap_params *params, void **state)
static const struct video_capture_info vidcap_bluefish444_info
#define BUFFERS
static void signal_error(struct vidcap_bluefish444_state *s)
#define MAX_BLUE_IN_CHANNELS
static bool should_exit_worker
bool UpdateVideoMode(struct vidcap_bluefish444_state *s, uint32_t VideoMode)
void RouteChannel(BLUEVELVETC_HANDLE pSDK, uint32_t Source, uint32_t Destination, uint32_t LinkType)
static bool setup_audio(struct vidcap_bluefish444_state *s, unsigned int flags)
static struct video_frame * vidcap_bluefish444_grab(void *state, struct audio_frame **audio)
static void vidcap_bluefish444_done(void *state)
static void parse_fmt(struct vidcap_bluefish444_state *s, char *fmt)
static void show_help(void)
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_AESEBU
AES/EBU audio.
#define VIDCAP_FLAG_AUDIO_EMBEDDED
HD-SDI embedded audio.
const char * get_interlacing_suffix(enum interlacing_t interlacing)
Returns suffix describing interlacing Eg. p, i or psf.