#include <thread>
#include <utility>
#include <vector>
+#include <arpa/inet.h>
#include "bmusb/bmusb.h"
#include "context.h"
+#include "decklink_capture.h"
#include "defs.h"
#include "flags.h"
#include "h264encode.h"
void convert_fixed24_to_fp32(float *dst, size_t out_channels, const uint8_t *src, size_t in_channels, size_t num_samples)
{
+ assert(in_channels >= out_channels);
for (size_t i = 0; i < num_samples; ++i) {
for (size_t j = 0; j < out_channels; ++j) {
uint32_t s1 = *src++;
}
}
+void convert_fixed32_to_fp32(float *dst, size_t out_channels, const uint8_t *src, size_t in_channels, size_t num_samples)
+{
+ assert(in_channels >= out_channels);
+ for (size_t i = 0; i < num_samples; ++i) {
+ for (size_t j = 0; j < out_channels; ++j) {
+ // Note: Assumes little-endian.
+ int32_t s = *(int32_t *)src;
+ dst[i * out_channels + j] = s * (1.0f / 4294967296.0f);
+ src += 4;
+ }
+ src += 4 * (in_channels - out_channels);
+ }
+}
+
void insert_new_frame(RefCountedFrame frame, unsigned field_num, bool interlaced, unsigned card_index, InputState *input_state)
{
if (interlaced) {
h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd));
- for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
- configure_card(card_index, format, new BMUSBCapture(card_index));
+ // First try initializing the PCI devices, then USB, until we have the desired number of cards.
+ unsigned num_pci_devices = 0, num_usb_devices = 0;
+ unsigned card_index = 0;
+
+ IDeckLinkIterator *decklink_iterator = CreateDeckLinkIteratorInstance();
+ if (decklink_iterator != nullptr) {
+ for ( ; card_index < num_cards; ++card_index) {
+ IDeckLink *decklink;
+ if (decklink_iterator->Next(&decklink) != S_OK) {
+ break;
+ }
+
+ configure_card(card_index, format, new DeckLinkCapture(decklink, card_index));
+ ++num_pci_devices;
+ }
+ decklink_iterator->Release();
+ fprintf(stderr, "Found %d DeckLink PCI card(s).\n", num_pci_devices);
+ } else {
+ fprintf(stderr, "DeckLink drivers not found. Probing for USB cards only.\n");
+ }
+ for ( ; card_index < num_cards; ++card_index) {
+ configure_card(card_index, format, new BMUSBCapture(card_index - num_pci_devices));
+ ++num_usb_devices;
}
- BMUSBCapture::start_bm_thread();
+ if (num_usb_devices > 0) {
+ BMUSBCapture::start_bm_thread();
+ }
- for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
+ for (card_index = 0; card_index < num_cards; ++card_index) {
cards[card_index].capture->start_bm_capture();
}
void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
FrameAllocator::Frame video_frame, size_t video_offset, VideoFormat video_format,
- FrameAllocator::Frame audio_frame, size_t audio_offset, uint16_t audio_format)
+ FrameAllocator::Frame audio_frame, size_t audio_offset, AudioFormat audio_format)
{
CaptureCard *card = &cards[card_index];
int64_t frame_length = int64_t(TIMEBASE * video_format.frame_rate_den) / video_format.frame_rate_nom;
- size_t num_samples = (audio_frame.len >= audio_offset) ? (audio_frame.len - audio_offset) / 8 / 3 : 0;
+ size_t num_samples = (audio_frame.len >= audio_offset) ? (audio_frame.len - audio_offset) / audio_format.num_channels / (audio_format.bits_per_sample / 8) : 0;
if (num_samples > OUTPUT_FREQUENCY / 10) {
printf("Card %d: Dropping frame with implausible audio length (len=%d, offset=%d) [timecode=0x%04x video_len=%d video_offset=%d video_format=%x)\n",
card_index, int(audio_frame.len), int(audio_offset),
// Convert the audio to stereo fp32 and add it.
vector<float> audio;
audio.resize(num_samples * 2);
- convert_fixed24_to_fp32(&audio[0], 2, audio_frame.data + audio_offset, 8, num_samples);
+ switch (audio_format.bits_per_sample) {
+ case 24:
+ convert_fixed24_to_fp32(&audio[0], 2, audio_frame.data + audio_offset, audio_format.num_channels, num_samples);
+ break;
+ case 32:
+ convert_fixed32_to_fp32(&audio[0], 2, audio_frame.data + audio_offset, audio_format.num_channels, num_samples);
+ break;
+ default:
+ fprintf(stderr, "Cannot handle audio with %u bits per sample\n", audio_format.bits_per_sample);
+ assert(false);
+ }
// Add the audio.
{
clock_gettime(CLOCK_MONOTONIC, &frame_upload_start);
}
userdata->last_interlaced = video_format.interlaced;
+ userdata->last_has_signal = video_format.has_signal;
userdata->last_frame_rate_nom = video_format.frame_rate_nom;
userdata->last_frame_rate_den = video_format.frame_rate_den;
RefCountedFrame new_frame(video_frame);