]> git.sesse.net Git - nageru/blobdiff - mixer.cpp
Start a mux only on a keyframe, so that transcoding clients do not get too confused.
[nageru] / mixer.cpp
index e8c9a758ad4f6c25bd6fb144cc565c1234ff7999..a1c038d5329abc21ad0e9a5015e0575f7658b959 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -50,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++;
@@ -62,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) {
@@ -314,9 +329,29 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
 {
        CaptureCard *card = &cards[card_index];
 
+       if (is_mode_scanning[card_index]) {
+               if (video_format.has_signal) {
+                       // Found a stable signal, so stop scanning.
+                       is_mode_scanning[card_index] = false;
+               } else {
+                       static constexpr double switch_time_s = 0.5;  // Should be enough time for the signal to stabilize.
+                       timespec now;
+                       clock_gettime(CLOCK_MONOTONIC, &now);
+                       double sec_since_last_switch = (now.tv_sec - last_mode_scan_change[card_index].tv_sec) +
+                               1e-9 * (now.tv_nsec - last_mode_scan_change[card_index].tv_nsec);
+                       if (sec_since_last_switch > switch_time_s) {
+                               // It isn't this mode; try the next one.
+                               mode_scanlist_index[card_index]++;
+                               mode_scanlist_index[card_index] %= mode_scanlist[card_index].size();
+                               cards[card_index].capture->set_video_mode(mode_scanlist[card_index][mode_scanlist_index[card_index]]);
+                               last_mode_scan_change[card_index] = now;
+                       }
+               }
+       }
+
        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),
@@ -343,6 +378,9 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
        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);
@@ -1019,6 +1057,23 @@ void Mixer::reset_meters()
        correlation.reset();
 }
 
+void Mixer::start_mode_scanning(unsigned card_index)
+{
+       assert(card_index < num_cards);
+       if (is_mode_scanning[card_index]) {
+               return;
+       }
+       is_mode_scanning[card_index] = true;
+       mode_scanlist[card_index].clear();
+       for (const auto &mode : cards[card_index].capture->get_available_video_modes()) {
+               mode_scanlist[card_index].push_back(mode.first);
+       }
+       assert(!mode_scanlist[card_index].empty());
+       mode_scanlist_index[card_index] = 0;
+       cards[card_index].capture->set_video_mode(mode_scanlist[card_index][0]);
+       clock_gettime(CLOCK_MONOTONIC, &last_mode_scan_change[card_index]);
+}
+
 Mixer::OutputChannel::~OutputChannel()
 {
        if (has_current_frame) {