]> git.sesse.net Git - nageru/blobdiff - mixer.cpp
Fix SBS for non-1280x720 resolutions.
[nageru] / mixer.cpp
index 5f023cfd691eba9e0723e6f92c5ca4e6adb82519..d725ad36b8fe84415d1b92f6201510b978029f2d 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
 #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"
@@ -48,6 +50,7 @@ namespace {
 
 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++;
@@ -60,6 +63,20 @@ void convert_fixed24_to_fp32(float *dst, size_t out_channels, const uint8_t *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) {
@@ -135,13 +152,36 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
 
        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();
        }
 
@@ -285,13 +325,13 @@ void deinterleave_samples(const vector<float> &in, vector<float> *out_l, vector<
 
 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),
@@ -314,7 +354,17 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
        // 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.
        {
@@ -405,6 +455,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                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);