X-Git-Url: https://git.sesse.net/?p=nageru;a=blobdiff_plain;f=x264_encoder.h;h=687bf718679c316a3b2e6a24a41c8e449d79c776;hp=729cb7f02bcc0063861aa946ec700e6321e566b8;hb=327534a3031a332423411c9599c741f2f81657df;hpb=3be00c8dd8b841cecc44f57234b9fc2d3a94cb45 diff --git a/x264_encoder.h b/x264_encoder.h index 729cb7f..687bf71 100644 --- a/x264_encoder.h +++ b/x264_encoder.h @@ -3,34 +3,42 @@ // so a little under 100 MB at 720p), then have a separate thread pull out // those threads as fast as we can to give it to x264 for encoding. // -// TODO: We use x264's “speedcontrol” patch if available, so that quality is -// automatically scaled up or down to content and available CPU time. -// // The encoding threads are niced down because mixing is more important than // encoding; if we lose frames in mixing, we'll lose frames to disk _and_ // to the stream, as where if we lose frames in encoding, we'll lose frames // to the stream only, so the latter is strictly better. More importantly, -// this allows speedcontrol (when implemented) to do its thing without -// disturbing the mixer. +// this allows speedcontrol to do its thing without disturbing the mixer. #ifndef _X264ENCODE_H #define _X264ENCODE_H 1 +#include #include - +#include #include +#include #include #include #include -#include #include +#include +#include +#include +#include extern "C" { -#include "x264.h" #include } +#include + +#include "defs.h" +#include "metrics.h" +#include "print_latency.h" +#include "x264_dynamic.h" + class Mux; +class X264SpeedControl; class X264Encoder { public: @@ -41,37 +49,56 @@ public: ~X264Encoder(); // Must be called before first frame. Does not take ownership. - void set_mux(Mux *mux) { this->mux = mux; } + void add_mux(Mux *mux) { muxes.push_back(mux); } // is taken to be raw NV12 data of WIDTHxHEIGHT resolution. // Does not block. - void add_frame(int64_t pts, int64_t duration, const uint8_t *data); + void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts); + + std::string get_global_headers() const { + while (!x264_init_done) { + sched_yield(); + } + return global_headers; + } - std::string get_global_headers() const { return global_headers; } + void change_bitrate(unsigned rate_kbit) { + new_bitrate_kbit = rate_kbit; + } private: struct QueuedFrame { int64_t pts, duration; + movit::YCbCrLumaCoefficients ycbcr_coefficients; uint8_t *data; + ReceivedTimestamps received_ts; }; void encoder_thread_func(); void init_x264(); void encode_frame(QueuedFrame qf); + // bitrate_kbit can be 0 for no change. + static void speed_control_override_func(unsigned bitrate_kbit, movit::YCbCrLumaCoefficients coefficients, x264_param_t *param); + // One big memory chunk of all 50 (or whatever) frames, allocated in // the constructor. All data functions just use pointers into this // pool. std::unique_ptr frame_pool; - Mux *mux = nullptr; + std::vector muxes; bool wants_global_headers; std::string global_headers; std::string buffered_sei; // Will be output before first frame, if any. std::thread encoder_thread; + std::atomic x264_init_done{false}; std::atomic should_quit{false}; + X264Dynamic dyn; x264_t *x264; + std::unique_ptr speed_control; + + std::atomic new_bitrate_kbit{0}; // 0 for no change. // Protects everything below it. std::mutex mu; @@ -86,6 +113,9 @@ private: // Whenever the state of changes. std::condition_variable queued_frames_nonempty; + + // Key is the pts of the frame. + std::unordered_map frames_being_encoded; }; #endif // !defined(_X264ENCODE_H)