X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=bmusb%2Fbmusb.h;h=a484496bd6be5cd0aa83512258c0e87f75a79978;hb=HEAD;hp=f4af6aa14b2a1399168d3f75673b1d2215846770;hpb=8c728daab202458bba567bb4e5c1d0cbe2f8ab9c;p=bmusb diff --git a/bmusb/bmusb.h b/bmusb/bmusb.h index f4af6aa..cec84d9 100644 --- a/bmusb/bmusb.h +++ b/bmusb/bmusb.h @@ -4,11 +4,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -29,6 +31,7 @@ class FrameAllocator { struct Frame { uint8_t *data = nullptr; uint8_t *data2 = nullptr; // Only if interleaved == true. + uint8_t *data_copy = nullptr; // Will get a non-interleaved copy if not nullptr. size_t len = 0; // Number of bytes we actually have. size_t size = 0; // Number of bytes we have room for. size_t overflow = 0; @@ -38,7 +41,18 @@ class FrameAllocator { // If set to true, every other byte will go to data and to data2. // If so, and are still about the number of total bytes // so if size == 1024, there's 512 bytes in data and 512 in data2. + // + // This doesn't really make any sense if you asked for the + // 10BitYCbCr pixel format. bool interleaved = false; + + // At what point this frame was received. Note that this marks the + // _end_ of the frame being received, not the beginning. + // Thus, if you want to measure latency, you'll also need to include + // the time the frame actually took to transfer (usually 1/fps, + // ie., the frames are typically transferred in real time). + std::chrono::steady_clock::time_point received_timestamp = + std::chrono::steady_clock::time_point::min(); }; virtual ~FrameAllocator(); @@ -59,6 +73,22 @@ class FrameAllocator { // if so, the frame in progress will be dropped. virtual Frame alloc_frame() = 0; + // Similar to alloc_frame(), with two additional restrictions: + // + // - The width, height and stride given must be correct + // (can not be changed after the call). + // - create_frame(), unlike alloc_frame(), is allowed to sleep + // (so bmusb will never call it, but in Nageru, other producers + // might) + // + // These two restrictions are relevant for Nageru, since it means that + // it can make frame_copy point directly into a VA-API buffer to avoid + // an extra copy. + virtual Frame create_frame(size_t width, size_t height, size_t stride) + { + return alloc_frame(); + } + virtual void release_frame(Frame frame) = 0; }; @@ -93,14 +123,17 @@ struct VideoMode { // Represents the format of an actual frame coming in. // Note: Frame rate is _frame_ rate, not field rate. So 1080i60 gets 30/1, _not_ 60/1. -// "second_field_start" is only valid for interlaced modes; it signifies -// how many lines from the very top of the frame there are before the second field +// "second_field_start" is only valid for interlaced modes. If it is 1, +// the two fields are actually stored interlaced (ie., every other line). +// If not, each field is stored consecutively, and it signifies how many lines +// from the very top of the frame there are before the second field // starts (so it will always be >= height/2 + extra_lines_top). struct VideoFormat { uint16_t id = 0; // For debugging/logging only. unsigned width = 0, height = 0, second_field_start = 0; unsigned extra_lines_top = 0, extra_lines_bottom = 0; unsigned frame_rate_nom = 0, frame_rate_den = 0; + unsigned stride = 0; // In bytes, assuming no interleaving. bool interlaced = false; bool has_signal = false; bool is_connected = true; // If false, then has_signal makes no sense. @@ -110,6 +143,49 @@ struct AudioFormat { uint16_t id = 0; // For debugging/logging only. unsigned bits_per_sample = 0; unsigned num_channels = 0; + unsigned sample_rate = 48000; +}; + +enum PixelFormat { + // 8-bit 4:2:2 in the standard Cb Y Cr Y order (UYVY). + // This is the default. + PixelFormat_8BitYCbCr, + + // 10-bit 4:2:2 in v210 order. Six pixels (six Y', three Cb, + // three Cr) are packed into four 32-bit little-endian ints + // in the following pattern (see e.g. the DeckLink documentation + // for reference): + // + // A B G R + // ----------------- + // X Cr0 Y0 Cb0 + // X Y2 Cb2 Y1 + // X Cb4 Y3 Cr2 + // X Y5 Cr4 Y4 + // + // If you read in RGB order and ignore the unused top bits, + // this is essentially Cb Y Cr Y order, just like UYVY is. + // + // Note that unlike true v210, there is no guarantee about + // 128-byte line alignment (or lack thereof); you should check + // the stride member of VideoFormat. + PixelFormat_10BitYCbCr, + + // 8-bit 4:4:4:4 BGRA (in that order). bmusb itself doesn't + // produce this, but it is useful to represent e.g. synthetic inputs. + PixelFormat_8BitBGRA, + + // 8-bit 4:2:0, 4:2:2, 4:4:4 or really anything else, planar + // (ie., first all Y', then all Cb, then all Cr). bmusb doesn't + // produce this, nor does it specify a mechanism to describe + // the precise details of the format. + PixelFormat_8BitYCbCrPlanar, + + // These exist only so that the type is guaranteed wide enough + // to contain values up to 127. CaptureInterface instances + // are free to use them as they see fit for private uses. + PixelFormat_Unused100 = 100, + PixelFormat_Unused127 = 127 }; typedef std::function get_available_pixel_formats() const = 0; + virtual void set_pixel_format(PixelFormat pixel_format) = 0; + virtual PixelFormat get_current_pixel_format() const = 0; + virtual std::map get_available_video_inputs() const = 0; virtual void set_video_input(uint32_t video_input_id) = 0; virtual uint32_t get_current_video_input() const = 0; @@ -179,6 +260,18 @@ class BMUSBCapture : public CaptureInterface { // actually opening the card (in configure_card()). static unsigned num_cards(); + std::set get_available_pixel_formats() const override + { + return std::set{ PixelFormat_8BitYCbCr, PixelFormat_10BitYCbCr }; + } + + void set_pixel_format(PixelFormat pixel_format) override; + + PixelFormat get_current_pixel_format() const + { + return current_pixel_format; + } + std::map get_available_video_modes() const override; uint32_t get_current_video_mode() const override; void set_video_mode(uint32_t video_mode_id) override; @@ -331,6 +424,7 @@ class BMUSBCapture : public CaptureInterface { libusb_device_handle *devh = nullptr; uint32_t current_video_input = 0x00000000; // HDMI/SDI. uint32_t current_audio_input = 0x00000000; // Embedded. + PixelFormat current_pixel_format = PixelFormat_8BitYCbCr; bool disconnected = false; };