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