]> git.sesse.net Git - nageru/blob - nageru/av1_encoder.h
IWYU-fix nageru/*.h.
[nageru] / nageru / av1_encoder.h
1 // An AV1 encoder using the SVT-AV1 encoder library. (libaom does not seem
2 // to be suitable for real-time streaming as of 2022, as it is not using
3 // threads particularly efficiently.) AV1 is a newer format than H.264,
4 // obviously both for better and for worse: Higher coding efficiency
5 // (with sufficient amount of cores, SVT-AV1 is even better than x264
6 // at higher frame rates), but generally smaller ecosystem, no speed
7 // control, less sophisticated rate control, etc..
8 //
9 // We don't support storing AV1 to disk currently, only to HTTP.
10 // We also don't support hardware AV1 encoding, as hardware supporting it
11 // is very rare currently.
12 //
13 // Since SVT-AV1 does not support VFR, you need to declare the frame rate
14 // up-front, using the --av1-framerate flag. If the given frame rate is
15 // too high (ie., you are producing frames too slowly), rate control will get
16 // confused and use too little bitrate. If it is too low, Nageru will need to
17 // drop frames before input to the encoder.
18
19 #ifndef _AV1_ENCODER_H
20 #define _AV1_ENCODER_H 1
21
22 #include <sched.h>
23 #include <stdint.h>
24 #include <atomic>
25 #include <condition_variable>
26 #include <memory>
27 #include <mutex>
28 #include <queue>
29 #include <string>
30 #include <thread>
31 #include <unordered_map>
32 #include <vector>
33
34 extern "C" {
35 #include <libavformat/avformat.h>
36 }
37
38 #include <movit/image_format.h>
39
40 #include "print_latency.h"
41 #include "video_codec_interface.h"
42
43 class Mux;
44 struct EbBufferHeaderType;
45 struct EbComponentType;
46
47 class AV1Encoder : public VideoCodecInterface {
48 public:
49         AV1Encoder(const AVOutputFormat *oformat);  // Does not take ownership.
50
51         // Called after the last frame. Will block; once this returns,
52         // the last data is flushed.
53         ~AV1Encoder() override;
54
55         // Must be called before first frame. Does not take ownership.
56         void add_mux(Mux *mux) override { muxes.push_back(mux); }
57
58         // <data> is taken to be raw NV12 data of WIDTHxHEIGHT resolution.
59         // Does not block.
60         void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts) override;
61
62         std::string get_global_headers() const override {
63                 while (!av1_init_done) {
64                         sched_yield();
65                 }
66                 return global_headers;
67         }
68
69 private:
70         struct QueuedFrame {
71                 int64_t pts, duration;
72                 movit::YCbCrLumaCoefficients ycbcr_coefficients;
73                 uint8_t *data;
74                 ReceivedTimestamps received_ts;
75         };
76         void encoder_thread_func();
77         void init_av1();
78         void encode_frame(QueuedFrame qf);
79         void process_packet(EbBufferHeaderType *buf);  // Takes ownership.
80
81         // One big memory chunk of all 50 (or whatever) frames, allocated in
82         // the constructor. All data functions just use pointers into this
83         // pool.
84         std::unique_ptr<uint8_t[]> frame_pool;
85
86         std::vector<Mux *> muxes;
87         const bool wants_global_headers;
88
89         std::string global_headers;
90
91         std::thread encoder_thread;
92         std::atomic<bool> av1_init_done{false};
93         std::atomic<bool> should_quit{false};
94         EbComponentType *encoder;
95
96         int64_t last_pts = -1;
97
98         // Protects everything below it.
99         std::mutex mu;
100
101         // Frames that are not being encoded or waiting to be encoded,
102         // so that add_frame() can use new ones.
103         // TODO: Do we actually need this queue, or is SVT-AV1's queue
104         // non-blocking so that we can drop it?
105         std::queue<uint8_t *> free_frames;
106
107         // Frames that are waiting to be encoded (ie., add_frame() has been
108         // called, but they are not picked up for encoding yet).
109         std::queue<QueuedFrame> queued_frames;
110
111         // Whenever the state of <queued_frames> changes.
112         std::condition_variable queued_frames_nonempty;
113
114         // Key is the pts of the frame.
115         std::unordered_map<int64_t, ReceivedTimestamps> frames_being_encoded;
116 };
117
118 #endif  // !defined(_AV1_ENCODER_H)