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..
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.
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.
19 #ifndef _AV1_ENCODER_H
20 #define _AV1_ENCODER_H 1
25 #include <condition_variable>
31 #include <unordered_map>
35 #include <libavformat/avformat.h>
38 #include <movit/image_format.h>
40 #include "print_latency.h"
41 #include "video_codec_interface.h"
44 struct EbBufferHeaderType;
45 struct EbComponentType;
47 class AV1Encoder : public VideoCodecInterface {
49 AV1Encoder(const AVOutputFormat *oformat); // Does not take ownership.
51 // Called after the last frame. Will block; once this returns,
52 // the last data is flushed.
53 ~AV1Encoder() override;
55 // Must be called before first frame. Does not take ownership.
56 void add_mux(Mux *mux) override { muxes.push_back(mux); }
58 // <data> is taken to be raw NV12 data of WIDTHxHEIGHT resolution.
60 void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts) override;
62 std::string get_global_headers() const override {
63 while (!av1_init_done) {
66 return global_headers;
71 int64_t pts, duration;
72 movit::YCbCrLumaCoefficients ycbcr_coefficients;
74 ReceivedTimestamps received_ts;
76 void encoder_thread_func();
78 void encode_frame(QueuedFrame qf);
79 void process_packet(EbBufferHeaderType *buf); // Takes ownership.
81 // One big memory chunk of all 50 (or whatever) frames, allocated in
82 // the constructor. All data functions just use pointers into this
84 std::unique_ptr<uint8_t[]> frame_pool;
86 std::vector<Mux *> muxes;
87 const bool wants_global_headers;
89 std::string global_headers;
91 std::thread encoder_thread;
92 std::atomic<bool> av1_init_done{false};
93 std::atomic<bool> should_quit{false};
94 EbComponentType *encoder;
96 int64_t last_pts = -1;
98 // Protects everything below it.
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;
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;
111 // Whenever the state of <queued_frames> changes.
112 std::condition_variable queued_frames_nonempty;
114 // Key is the pts of the frame.
115 std::unordered_map<int64_t, ReceivedTimestamps> frames_being_encoded;
118 #endif // !defined(_AV1_ENCODER_H)