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.
6 // The encoding threads are niced down because mixing is more important than
7 // encoding; if we lose frames in mixing, we'll lose frames to disk _and_
8 // to the stream, as where if we lose frames in encoding, we'll lose frames
9 // to the stream only, so the latter is strictly better. More importantly,
10 // this allows speedcontrol to do its thing without disturbing the mixer.
13 #define _X264ENCODE_H 1
20 #include <condition_variable>
26 #include <unordered_map>
30 #include <libavformat/avformat.h>
33 #include <movit/image_format.h>
36 #include "shared/metrics.h"
37 #include "print_latency.h"
38 #include "video_codec_interface.h"
39 #include "x264_dynamic.h"
42 class X264SpeedControl;
44 class X264Encoder : public VideoCodecInterface {
46 X264Encoder(const AVOutputFormat *oformat, bool use_separate_disk_params); // Does not take ownership.
48 // Called after the last frame. Will block; once this returns,
49 // the last data is flushed.
50 ~X264Encoder() override;
52 // Must be called before first frame. Does not take ownership.
53 void add_mux(Mux *mux) override { muxes.push_back(mux); }
55 // <data> is taken to be raw NV12 data of WIDTHxHEIGHT resolution.
57 void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts) override;
59 std::string get_global_headers() const override {
60 while (!x264_init_done) {
63 return global_headers;
66 void change_bitrate(unsigned rate_kbit) {
67 new_bitrate_kbit = rate_kbit;
72 int64_t pts, duration;
73 movit::YCbCrLumaCoefficients ycbcr_coefficients;
75 ReceivedTimestamps received_ts;
77 void encoder_thread_func();
79 void encode_frame(QueuedFrame qf);
81 // bitrate_kbit can be 0 for no change.
82 static void speed_control_override_func(unsigned bitrate_kbit, movit::YCbCrLumaCoefficients coefficients, x264_param_t *param);
84 // One big memory chunk of all 50 (or whatever) frames, allocated in
85 // the constructor. All data functions just use pointers into this
87 std::unique_ptr<uint8_t[]> frame_pool;
89 std::vector<Mux *> muxes;
90 const bool wants_global_headers;
91 const bool use_separate_disk_params;
93 std::string global_headers;
94 std::string buffered_sei; // Will be output before first frame, if any.
96 std::thread encoder_thread;
97 std::atomic<bool> x264_init_done{false};
98 std::atomic<bool> should_quit{false};
101 std::unique_ptr<X264SpeedControl> speed_control;
103 std::atomic<unsigned> new_bitrate_kbit{0}; // 0 for no change.
105 // Protects everything below it.
108 // Frames that are not being encoded or waiting to be encoded,
109 // so that add_frame() can use new ones.
110 std::queue<uint8_t *> free_frames;
112 // Frames that are waiting to be encoded (ie., add_frame() has been
113 // called, but they are not picked up for encoding yet).
114 std::queue<QueuedFrame> queued_frames;
116 // Whenever the state of <queued_frames> changes.
117 std::condition_variable queued_frames_nonempty;
119 // Key is the pts of the frame.
120 std::unordered_map<int64_t, ReceivedTimestamps> frames_being_encoded;
123 #endif // !defined(_X264ENCODE_H)