]> git.sesse.net Git - nageru/blob - x264encode.h
Separate muxing entirely out of the HTTPD class.
[nageru] / x264encode.h
1 // A wrapper around x264, to encode video in higher quality than Quick Sync
2 // can give us. We maintain a queue of uncompressed Y'CbCr frames (of 50 frames,
3 // so a little under 100 MB at 720p), then have a separate thread pull out
4 // those threads as fast as we can to give it to x264 for encoding.
5 //
6 // TODO: We use x264's “speedcontrol” patch if available, so that quality is
7 // automatically scaled up or down to content and available CPU time.
8 //
9 // The encoding threads are niced down because mixing is more important than
10 // encoding; if we lose frames in mixing, we'll lose frames to disk _and_
11 // to the stream, as where if we lose frames in encoding, we'll lose frames
12 // to the stream only, so the latter is strictly better. More importantly,
13 // this allows speedcontrol (when implemented) to do its thing without
14 // disturbing the mixer.
15
16 #ifndef _X264ENCODE_H
17 #define _X264ENCODE_H 1
18
19 #include <stdint.h>
20
21 #include <condition_variable>
22 #include <memory>
23 #include <mutex>
24 #include <thread>
25 #include <queue>
26
27 extern "C" {
28 #include "x264.h"
29 }
30
31 class Mux;
32
33 class X264Encoder {
34 public:
35         X264Encoder(Mux *httpd);  // Does not take ownership.
36         ~X264Encoder();
37
38         // <data> is taken to be raw NV12 data of WIDTHxHEIGHT resolution.
39         // Does not block.
40         void add_frame(int64_t pts, const uint8_t *data);
41
42         // Called after the last frame. Will block; once this returns,
43         // the last data is flushed.
44         void end_encoding();
45
46 private:
47         struct QueuedFrame {
48                 int64_t pts;
49                 uint8_t *data;
50         };
51         void encoder_thread_func();
52         void init_x264();
53         void encode_frame(QueuedFrame qf);
54
55         // One big memory chunk of all 50 (or whatever) frames, allocated in
56         // the constructor. All data functions just use pointers into this
57         // pool.
58         std::unique_ptr<uint8_t[]> frame_pool;
59
60         Mux *mux = nullptr;
61
62         std::thread encoder_thread;
63         x264_t *x264;
64
65         // Protects everything below it.
66         std::mutex mu;
67
68         // Frames that are not being encoded or waiting to be encoded,
69         // so that add_frame() can use new ones.
70         std::queue<uint8_t *> free_frames;
71
72         // Frames that are waiting to be encoded (ie., add_frame() has been
73         // called, but they are not picked up for encoding yet).
74         std::queue<QueuedFrame> queued_frames;
75
76         // Whenever the state of <queued_frames> changes.
77         std::condition_variable queued_frames_nonempty;
78 };
79
80 #endif  // !defined(_X264ENCODE_H)