X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mux.h;h=e6193e0a36c92ec0258f3680df597a37f15ce26f;hb=b9feb66845bf24465b7671ac9ff7a52b88f6032b;hp=3f5007db9f75c6040415be1a01ce6ccd74059db0;hpb=b561d43a60201395f1354a585aa37670eda45883;p=nageru diff --git a/mux.h b/mux.h index 3f5007d..e6193e0 100644 --- a/mux.h +++ b/mux.h @@ -6,27 +6,63 @@ extern "C" { #include #include -#include } +#include +#include +#include #include #include -#include +#include +#include +#include #include +#include "timebase.h" + +struct MuxMetrics { + // “written” will usually be equal video + audio + mux overhead, + // except that there could be buffered packets that count in audio or video + // but not yet in written. + std::atomic metric_video_bytes{0}, metric_audio_bytes{0}, metric_written_bytes{0}; + + // Registers in global_metrics. + void init(const std::vector> &labels); + + void reset() + { + metric_video_bytes = 0; + metric_audio_bytes = 0; + metric_written_bytes = 0; + } +}; + class Mux { public: enum Codec { CODEC_H264, CODEC_NV12, // Uncompressed 4:2:0. }; + enum WriteStrategy { + // add_packet() will write the packet immediately, unless plugged. + WRITE_FOREGROUND, + + // All writes will happen on a separate thread, so add_packet() + // won't block. Use this if writing to a file and you might be + // holding a mutex (because blocking I/O with a mutex held is + // not good). Note that this will clone every packet, so it has + // higher overhead. + WRITE_BACKGROUND, + }; // Takes ownership of avctx. will be called every time // a write has been made to the video stream (id 0), with the pts of // the just-written frame. (write_callback can be nullptr.) - Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const std::string &video_extradata, const AVCodecParameters *audio_codecpar, int time_base, std::function write_callback); + // Does not take ownership of ; elements in there, if any, + // will be added to. + Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const std::string &video_extradata, const AVCodecParameters *audio_codecpar, int time_base, std::function write_callback, WriteStrategy write_strategy, const std::vector &metrics); ~Mux(); - void add_packet(const AVPacket &pkt, int64_t pts, int64_t dts); + void add_packet(const AVPacket &pkt, int64_t pts, int64_t dts, AVRational timebase = { 1, TIMEBASE }); // As long as the mux is plugged, it will not actually write anything to disk, // just queue the packets. Once it is unplugged, the packets are reordered by pts @@ -40,16 +76,36 @@ public: void unplug(); private: - void write_packet_or_die(const AVPacket &pkt); // Must be called with held. + // If write_strategy == WRITE_FOREGORUND, Must be called with held. + void write_packet_or_die(const AVPacket &pkt, int64_t unscaled_pts); + void thread_func(); + + WriteStrategy write_strategy; std::mutex mu; - AVFormatContext *avctx; // Protected by . + + // These are only in use if write_strategy == WRITE_BACKGROUND. + std::atomic writer_thread_should_quit{false}; + std::thread writer_thread; + + AVFormatContext *avctx; // Protected by , iff write_strategy == WRITE_BACKGROUND. int plug_count = 0; // Protected by . - std::vector plugged_packets; // Protected by . + + // Protected by . If write_strategy == WRITE_FOREGROUND, + // this is only in use when plugging. + struct QueuedPacket { + AVPacket *pkt; + int64_t unscaled_pts; + }; + std::vector packet_queue; + std::condition_variable packet_queue_ready; AVStream *avstream_video, *avstream_audio; std::function write_callback; + std::vector metrics; + + friend struct PacketBefore; }; #endif // !defined(_MUX_H)