From 11835ea0f6cb5f551f6dfc2106ab02779148fbf0 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 25 Jul 2016 14:17:45 +0200 Subject: [PATCH] Move FakeCapture into bmusb, and make it a little more generic. --- Makefile | 2 +- bmusb | 2 +- defs.h | 1 + fake_capture.cpp | 268 ----------------------------------------------- fake_capture.h | 103 ------------------ mixer.cpp | 6 +- 6 files changed, 6 insertions(+), 376 deletions(-) delete mode 100644 fake_capture.cpp delete mode 100644 fake_capture.h diff --git a/Makefile b/Makefile index fb171a7..a88b7f6 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o correlation_meter.moc.o aboutdialog.moc.o # Mixer objects -OBJS += mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o httpd.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_output.o correlation_measurer.o fake_capture.o +OBJS += mixer.o bmusb/bmusb.o bmusb/fake_capture.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o httpd.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_output.o correlation_measurer.o # Streaming and encoding objects OBJS += quicksync_encoder.o x264_encoder.o x264_speed_control.o video_encoder.o metacube2.o mux.o audio_encoder.o diff --git a/bmusb b/bmusb index c66728f..96c4143 160000 --- a/bmusb +++ b/bmusb @@ -1 +1 @@ -Subproject commit c66728fa32fc79abd5c4fb9188750cccf9039dee +Subproject commit 96c41434726ef4b603f58cc3cafbb1630bea269e diff --git a/defs.h b/defs.h index 05a3899..498ade9 100644 --- a/defs.h +++ b/defs.h @@ -5,6 +5,7 @@ #define MAX_FPS 60 #define WIDTH 1280 #define HEIGHT 720 +#define FAKE_FPS 25 // Must be an integer. #define MAX_CARDS 16 // For deinterlacing. See also comments on InputState. diff --git a/fake_capture.cpp b/fake_capture.cpp deleted file mode 100644 index 7d23d8c..0000000 --- a/fake_capture.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// A fake capture device that sends single-color frames at a given rate. -// Mostly useful for testing themes without actually hooking up capture devices. - -#include "fake_capture.h" - -#include -#include -#include -#include -#include -#include -#include -#if __SSE2__ -#include -#endif -#include - -#include "bmusb/bmusb.h" -#include "defs.h" - -#define FRAME_SIZE (8 << 20) // 8 MB. -#define FAKE_FPS 25 // Must be an integer. - -// Pure-color inputs: Red, green, blue, white. -#define NUM_COLORS 4 -constexpr uint8_t ys[NUM_COLORS] = { 81, 145, 41, 235 }; -constexpr uint8_t cbs[NUM_COLORS] = { 90, 54, 240, 128 }; -constexpr uint8_t crs[NUM_COLORS] = { 240, 34, 110, 128 }; - -using namespace std; - -namespace bmusb { -namespace { - -void memset2(uint8_t *s, const uint8_t c[2], size_t n) -{ - size_t i = 0; -#if __SSE2__ - const uint8_t c_expanded[16] = { - c[0], c[1], c[0], c[1], c[0], c[1], c[0], c[1], - c[0], c[1], c[0], c[1], c[0], c[1], c[0], c[1] - }; - __m128i cc = *(__m128i *)c_expanded; - __m128i *out = (__m128i *)s; - - for ( ; i < (n & ~15); i += 16) { - _mm_storeu_si128(out++, cc); - _mm_storeu_si128(out++, cc); - } - - s = (uint8_t *)out; -#endif - for ( ; i < n; ++i) { - *s++ = c[0]; - *s++ = c[1]; - } -} - -void memset4(uint8_t *s, const uint8_t c[4], size_t n) -{ - size_t i = 0; -#if __SSE2__ - const uint8_t c_expanded[16] = { - c[0], c[1], c[2], c[3], c[0], c[1], c[2], c[3], - c[0], c[1], c[2], c[3], c[0], c[1], c[2], c[3] - }; - __m128i cc = *(__m128i *)c_expanded; - __m128i *out = (__m128i *)s; - - for ( ; i < (n & ~7); i += 8) { - _mm_storeu_si128(out++, cc); - _mm_storeu_si128(out++, cc); - } - - s = (uint8_t *)out; -#endif - for ( ; i < n; ++i) { - *s++ = c[0]; - *s++ = c[1]; - *s++ = c[2]; - *s++ = c[3]; - } -} - -} // namespace - -FakeCapture::FakeCapture(int card_index) -{ - char buf[256]; - snprintf(buf, sizeof(buf), "Fake card %d", card_index + 1); - description = buf; - - y = ys[card_index % NUM_COLORS]; - cb = cbs[card_index % NUM_COLORS]; - cr = crs[card_index % NUM_COLORS]; -} - -FakeCapture::~FakeCapture() -{ - if (has_dequeue_callbacks) { - dequeue_cleanup_callback(); - } -} - -void FakeCapture::configure_card() -{ - if (video_frame_allocator == nullptr) { - owned_video_frame_allocator.reset(new MallocFrameAllocator(FRAME_SIZE, NUM_QUEUED_VIDEO_FRAMES)); - set_video_frame_allocator(owned_video_frame_allocator.get()); - } - if (audio_frame_allocator == nullptr) { - owned_audio_frame_allocator.reset(new MallocFrameAllocator(65536, NUM_QUEUED_AUDIO_FRAMES)); - set_audio_frame_allocator(owned_audio_frame_allocator.get()); - } -} - -void FakeCapture::start_bm_capture() -{ - producer_thread_should_quit = false; - producer_thread = thread(&FakeCapture::producer_thread_func, this); -} - -void FakeCapture::stop_dequeue_thread() -{ - producer_thread_should_quit = true; - producer_thread.join(); -} - -std::map FakeCapture::get_available_video_modes() const -{ - VideoMode mode; - - char buf[256]; - snprintf(buf, sizeof(buf), "%dx%d", WIDTH, HEIGHT); - mode.name = buf; - - mode.autodetect = false; - mode.width = WIDTH; - mode.height = HEIGHT; - mode.frame_rate_num = FAKE_FPS; - mode.frame_rate_den = 1; - mode.interlaced = false; - - return {{ 0, mode }}; -} - -std::map FakeCapture::get_available_video_inputs() const -{ - return {{ 0, "Fake video input (single color)" }}; -} - -std::map FakeCapture::get_available_audio_inputs() const -{ - return {{ 0, "Fake audio input (silence)" }}; -} - -void FakeCapture::set_video_mode(uint32_t video_mode_id) -{ - assert(video_mode_id == 0); -} - -void FakeCapture::set_video_input(uint32_t video_input_id) -{ - assert(video_input_id == 0); -} - -void FakeCapture::set_audio_input(uint32_t audio_input_id) -{ - assert(audio_input_id == 0); -} - -namespace { - -void add_time(double t, timespec *ts) -{ - ts->tv_nsec += lrint(t * 1e9); - ts->tv_sec += ts->tv_nsec / 1000000000; - ts->tv_nsec %= 1000000000; -} - -bool timespec_less_than(const timespec &a, const timespec &b) -{ - return make_pair(a.tv_sec, a.tv_nsec) < make_pair(b.tv_sec, b.tv_nsec); -} - -} // namespace - -void FakeCapture::producer_thread_func() -{ - uint16_t timecode = 0; - - if (has_dequeue_callbacks) { - dequeue_init_callback(); - } - - timespec next_frame; - clock_gettime(CLOCK_MONOTONIC, &next_frame); - add_time(1.0 / FAKE_FPS, &next_frame); - - while (!producer_thread_should_quit) { - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - if (timespec_less_than(now, next_frame)) { - // Wait until the next frame. - if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, - &next_frame, nullptr) == -1) { - if (errno == EINTR) continue; // Re-check the flag and then sleep again. - perror("clock_nanosleep"); - exit(1); - } - } else { - // We've seemingly missed a frame. If we're more than one second behind, - // reset the timer; otherwise, just keep going. - timespec limit = next_frame; - ++limit.tv_sec; - if (!timespec_less_than(now, limit)) { - fprintf(stderr, "More than one second of missed fake frames; resetting clock.\n"); - next_frame = now; - } - } - - // Figure out when the next frame is to be, then compute the current one. - add_time(1.0 / FAKE_FPS, &next_frame); - - VideoFormat video_format; - video_format.width = WIDTH; - video_format.height = HEIGHT; - video_format.frame_rate_nom = FAKE_FPS; - video_format.frame_rate_den = 1; - video_format.has_signal = true; - video_format.is_connected = false; - - FrameAllocator::Frame video_frame = video_frame_allocator->alloc_frame(); - if (video_frame.data != nullptr) { - assert(video_frame.size >= WIDTH * HEIGHT * 2); - if (video_frame.interleaved) { - uint8_t cbcr[] = { cb, cr }; - memset2(video_frame.data, cbcr, WIDTH * HEIGHT / 2); - memset(video_frame.data2, y, WIDTH * HEIGHT); - } else { - uint8_t ycbcr[] = { y, cb, y, cr }; - memset4(video_frame.data, ycbcr, WIDTH * HEIGHT / 2); - } - video_frame.len = WIDTH * HEIGHT * 2; - } - - AudioFormat audio_format; - audio_format.bits_per_sample = 32; - audio_format.num_channels = 2; - - FrameAllocator::Frame audio_frame = audio_frame_allocator->alloc_frame(); - if (audio_frame.data != nullptr) { - assert(audio_frame.size >= 2 * sizeof(uint32_t) * OUTPUT_FREQUENCY / FAKE_FPS); - audio_frame.len = 2 * sizeof(uint32_t) * OUTPUT_FREQUENCY / FAKE_FPS; - memset(audio_frame.data, 0, audio_frame.len); - } - - frame_callback(timecode++, - video_frame, 0, video_format, - audio_frame, 0, audio_format); - } - if (has_dequeue_callbacks) { - dequeue_cleanup_callback(); - } -} - -} // namespace bmusb diff --git a/fake_capture.h b/fake_capture.h deleted file mode 100644 index 84a8953..0000000 --- a/fake_capture.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _FAKE_CAPTURE_H -#define _FAKE_CAPTURE_H 1 - -#include -#include -#include - -#include "bmusb/bmusb.h" - -namespace bmusb { - -class FakeCapture : public CaptureInterface -{ -public: - FakeCapture(int card_index); - ~FakeCapture(); - - // CaptureInterface. - void set_video_frame_allocator(FrameAllocator *allocator) override - { - video_frame_allocator = allocator; - if (owned_video_frame_allocator.get() != allocator) { - owned_video_frame_allocator.reset(); - } - } - - FrameAllocator *get_video_frame_allocator() override - { - return video_frame_allocator; - } - - // Does not take ownership. - void set_audio_frame_allocator(FrameAllocator *allocator) override - { - audio_frame_allocator = allocator; - if (owned_audio_frame_allocator.get() != allocator) { - owned_audio_frame_allocator.reset(); - } - } - - FrameAllocator *get_audio_frame_allocator() override - { - return audio_frame_allocator; - } - - void set_frame_callback(frame_callback_t callback) override - { - frame_callback = callback; - } - - void set_dequeue_thread_callbacks(std::function init, std::function cleanup) override - { - dequeue_init_callback = init; - dequeue_cleanup_callback = cleanup; - has_dequeue_callbacks = true; - } - - std::string get_description() const override - { - return description; - } - - void configure_card() override; - void start_bm_capture() override; - void stop_dequeue_thread() override; - bool get_disconnected() const override { return false; } - - std::map get_available_video_modes() const override; - void set_video_mode(uint32_t video_mode_id) override; - uint32_t get_current_video_mode() const override { return 0; } - - std::map get_available_video_inputs() const override; - void set_video_input(uint32_t video_input_id) override; - uint32_t get_current_video_input() const override { return 0; } - - std::map get_available_audio_inputs() const override; - void set_audio_input(uint32_t audio_input_id) override; - uint32_t get_current_audio_input() const override { return 0; } - -private: - void producer_thread_func(); - - uint8_t y, cb, cr; - - bool has_dequeue_callbacks = false; - std::function dequeue_init_callback = nullptr; - std::function dequeue_cleanup_callback = nullptr; - - FrameAllocator *video_frame_allocator = nullptr; - FrameAllocator *audio_frame_allocator = nullptr; - std::unique_ptr owned_video_frame_allocator; - std::unique_ptr owned_audio_frame_allocator; - frame_callback_t frame_callback = nullptr; - - std::string description; - - std::atomic producer_thread_should_quit{false}; - std::thread producer_thread; -}; - -} // namespace bmusb - -#endif // !defined(_FAKE_CAPTURE_H) diff --git a/mixer.cpp b/mixer.cpp index 6bc8780..e087796 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -31,10 +31,10 @@ #include #include "bmusb/bmusb.h" +#include "bmusb/fake_capture.h" #include "context.h" #include "decklink_capture.h" #include "defs.h" -#include "fake_capture.h" #include "flags.h" #include "video_encoder.h" #include "pbo_frame_allocator.h" @@ -178,7 +178,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) assert(num_fake_cards <= num_cards); // Enforced in flags.cpp. for ( ; card_index < num_fake_cards; ++card_index) { - configure_card(card_index, new FakeCapture(card_index), /*is_fake_capture=*/true); + configure_card(card_index, new FakeCapture(WIDTH, HEIGHT, FAKE_FPS, OUTPUT_FREQUENCY, card_index), /*is_fake_capture=*/true); } if (global_flags.num_fake_cards > 0) { @@ -824,7 +824,7 @@ void Mixer::handle_hotplugged_cards() CaptureCard *card = &cards[card_index]; if (card->capture->get_disconnected()) { fprintf(stderr, "Card %u went away, replacing with a fake card.\n", card_index); - configure_card(card_index, new FakeCapture(card_index), /*is_fake_capture=*/true); + configure_card(card_index, new FakeCapture(WIDTH, HEIGHT, FAKE_FPS, OUTPUT_FREQUENCY, card_index), /*is_fake_capture=*/true); card->queue_length_policy.reset(card_index); card->capture->start_bm_capture(); } -- 2.39.2