]> git.sesse.net Git - bmusb/blobdiff - fake_capture.cpp
Support 10-bit capture.
[bmusb] / fake_capture.cpp
index 29b06b100d016d49543114c0056a6c31e4bf05dd..5f4f5da4ea5904e9d7186eb9eef98003de1644be 100644 (file)
@@ -87,6 +87,26 @@ void memset4(uint8_t *s, const uint8_t c[4], size_t n)
        }
 }
 
+void memset16(uint8_t *s, const uint32_t c[4], size_t n)
+{
+       size_t i = 0;
+#if __SSE2__
+       __m128i cc = *(__m128i *)c;
+       __m128i *out = (__m128i *)s;
+
+       for ( ; i < (n & ~1); i += 2) {
+               _mm_storeu_si128(out++, cc);
+               _mm_storeu_si128(out++, cc);
+       }
+
+       s = (uint8_t *)out;
+#endif
+       for ( ; i < n; ++i) {
+               memcpy(s, c, 16);
+               s += 16;
+       }
+}
+
 }  // namespace
 
 FakeCapture::FakeCapture(unsigned width, unsigned height, unsigned fps, unsigned audio_sample_frequency, int card_index, bool has_audio)
@@ -238,6 +258,7 @@ void FakeCapture::producer_thread_func()
                                next_frame = now;
                        }
                }
+               steady_clock::time_point timestamp = steady_clock::now();
 
                // Figure out when the next frame is to be, then compute the current one.
                add_time(1.0 / fps, &next_frame);
@@ -245,6 +266,11 @@ void FakeCapture::producer_thread_func()
                VideoFormat video_format;
                video_format.width = width;
                video_format.height = height;
+               if (current_pixel_format == PixelFormat_10BitYCbCr) {
+                       video_format.stride = (width + 5) / 6 * 4 * sizeof(uint32_t);
+               } else {
+                       video_format.stride = width * 2;
+               }
                video_format.frame_rate_nom = fps;
                video_format.frame_rate_den = 1;
                video_format.has_signal = true;
@@ -254,15 +280,27 @@ void FakeCapture::producer_thread_func()
                if (video_frame.data != nullptr) {
                        assert(video_frame.size >= width * height * 2);
                        if (video_frame.interleaved) {
+                               assert(current_pixel_format == PixelFormat_8BitYCbCr);
                                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);
+                               if (current_pixel_format == PixelFormat_10BitYCbCr) {
+                                       // Just use the 8-bit-values shifted left by 2.
+                                       // It's not 100% correct, but it's close enough.
+                                       uint32_t pix[4];
+                                       pix[0] = (cb << 2) | (y  << 12) | (cr << 22);
+                                       pix[1] = (y  << 2) | (cb << 12) | ( y << 22);
+                                       pix[2] = (cr << 2) | (y  << 12) | (cb << 22);
+                                       pix[3] = (y  << 2) | (cr << 12) | ( y << 22);
+                                       memset16(video_frame.data, pix, video_format.stride * height / sizeof(pix));
+                               } else {
+                                       uint8_t ycbcr[] = { y, cb, y, cr };
+                                       memset4(video_frame.data, ycbcr, width * height / 2);
+                               }
                        }
-                       video_frame.len = width * height * 2;
-                       video_frame.received_timestamp = steady_clock::now();
+                       video_frame.len = video_format.stride * height;
+                       video_frame.received_timestamp = timestamp;
                }
 
                AudioFormat audio_format;
@@ -274,7 +312,7 @@ void FakeCapture::producer_thread_func()
                        const unsigned num_stereo_samples = audio_sample_frequency / fps;
                        assert(audio_frame.size >= audio_format.num_channels * sizeof(int32_t) * num_stereo_samples);
                        audio_frame.len = audio_format.num_channels * sizeof(int32_t) * num_stereo_samples;
-                       audio_frame.received_timestamp = steady_clock::now();
+                       audio_frame.received_timestamp = timestamp;
 
                        if (audio_sin == 0.0f) {
                                // Silence.