]> git.sesse.net Git - bmusb/blob - bmusb.h
Support multiple cards at the same time (although currently, they have to be of diffe...
[bmusb] / bmusb.h
1 #ifndef _BMUSB_H
2 #define _BMUSB_H
3
4 #include <stdint.h>
5 #include <atomic>
6 #include <condition_variable>
7 #include <deque>
8 #include <functional>
9 #include <mutex>
10 #include <thread>
11 #include <vector>
12
13 // An interface for frame allocators; if you do not specify one
14 // (using set_video_frame_allocator), a default one that pre-allocates
15 // a freelist of eight frames using new[] will be used. Specifying
16 // your own can be useful if you have special demands for where you want the
17 // frame to end up and don't want to spend the extra copy to get it there, for
18 // instance GPU memory.
19 class FrameAllocator {
20  public:
21         struct Frame {
22                 uint8_t *data = nullptr;
23                 uint8_t *data2 = nullptr;  // Only if interleaved == true.
24                 size_t len = 0;  // Number of bytes we actually have.
25                 size_t size = 0;  // Number of bytes we have room for.
26                 void *userdata = nullptr;
27                 FrameAllocator *owner = nullptr;
28
29                 // If set to true, every other byte will go to data and to data2.
30                 // If so, <len> and <size> are still about the number of total bytes
31                 // so if size == 1024, there's 512 bytes in data and 512 in data2.
32                 bool interleaved = false;
33         };
34
35         virtual ~FrameAllocator();
36
37         // Request a video frame. Note that this is called from the
38         // USB thread, which runs with realtime priority and is
39         // very sensitive to delays. Thus, you should not do anything
40         // here that might sleep, including calling malloc().
41         // (Taking a mutex is borderline.)
42         //
43         // The Frame object will be given to the frame callback,
44         // which is responsible for releasing the video frame back
45         // once it is usable for new frames (ie., it will no longer
46         // be read from). You can use the "userdata" pointer for
47         // whatever you want to identify this frame if you need to.
48         //
49         // Returning a Frame with data==nullptr is allowed;
50         // if so, the frame in progress will be dropped.
51         virtual Frame alloc_frame() = 0;
52
53         virtual void release_frame(Frame frame) = 0;
54 };
55
56 typedef std::function<void(uint16_t timecode,
57                            FrameAllocator::Frame video_frame, size_t video_offset, uint16_t video_format,
58                            FrameAllocator::Frame audio_frame, size_t audio_offset, uint16_t audio_format)>
59         frame_callback_t;
60
61 // The actual capturing class, representing capture from a single card.
62 class BMUSBCapture {
63  public:
64         BMUSBCapture(int vid = 0x1edb, int pid = 0xbd3b)
65                 : vid(vid), pid(pid)
66         {
67         }
68
69         // Does not take ownership.
70         void set_video_frame_allocator(FrameAllocator *allocator)
71         {
72                 video_frame_allocator = allocator;
73         }
74
75         FrameAllocator *get_video_frame_allocator()
76         {
77                 return video_frame_allocator;
78         }
79
80         // Does not take ownership.
81         void set_audio_frame_allocator(FrameAllocator *allocator)
82         {
83                 audio_frame_allocator = allocator;
84         }
85
86         FrameAllocator *get_audio_frame_allocator()
87         {
88                 return audio_frame_allocator;
89         }
90
91         void set_frame_callback(frame_callback_t callback)
92         {
93                 frame_callback = callback;
94         }
95
96         void configure_card();
97         void start_bm_capture();
98
99         static void start_bm_thread();
100         static void stop_bm_thread();
101
102  private:
103         struct QueuedFrame {
104                 uint16_t timecode;
105                 uint16_t format;
106                 FrameAllocator::Frame frame;
107         };
108
109         void start_new_audio_block(const uint8_t *start);
110         void start_new_frame(const uint8_t *start);
111
112         void queue_frame(uint16_t format, uint16_t timecode, FrameAllocator::Frame frame, std::deque<QueuedFrame> *q);
113         void dequeue_thread();
114
115         static void usb_thread_func();
116         static void cb_xfr(struct libusb_transfer *xfr);
117
118         FrameAllocator::Frame current_video_frame;
119         FrameAllocator::Frame current_audio_frame;
120
121         std::mutex queue_lock;
122         std::condition_variable queues_not_empty;
123         std::deque<QueuedFrame> pending_video_frames;
124         std::deque<QueuedFrame> pending_audio_frames;
125
126         FrameAllocator *video_frame_allocator = nullptr;
127         FrameAllocator *audio_frame_allocator = nullptr;
128         frame_callback_t frame_callback = nullptr;
129
130         int current_register = 0;
131
132         static constexpr int NUM_BMUSB_REGISTERS = 60;
133         uint8_t register_file[NUM_BMUSB_REGISTERS];
134
135         int vid, pid;
136         std::vector<libusb_transfer *> iso_xfrs;
137 };
138
139 #endif