From bc0683200d63d2fd0d49c0b998885c8b4d9db77e Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 12 Jun 2017 20:06:00 +0200 Subject: [PATCH] Added some mux metrics. --- mux.cpp | 39 +++++++++++++++++++++++++++++++++++++-- mux.h | 24 +++++++++++++++++++++++- quicksync_encoder.cpp | 11 ++++++++++- video_encoder.cpp | 3 ++- video_encoder.h | 2 ++ 5 files changed, 74 insertions(+), 5 deletions(-) diff --git a/mux.cpp b/mux.cpp index 1fd8e30..d01c180 100644 --- a/mux.cpp +++ b/mux.cpp @@ -23,6 +23,7 @@ extern "C" { #include "defs.h" #include "flags.h" +#include "metrics.h" #include "timebase.h" using namespace std; @@ -45,8 +46,8 @@ struct PacketBefore { const AVFormatContext * const ctx; }; -Mux::Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const string &video_extradata, const AVCodecParameters *audio_codecpar, int time_base, std::function write_callback) - : avctx(avctx), write_callback(write_callback) +Mux::Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const string &video_extradata, const AVCodecParameters *audio_codecpar, int time_base, std::function write_callback, const vector &metrics) + : avctx(avctx), write_callback(write_callback), metrics(metrics) { avstream_video = avformat_new_stream(avctx, nullptr); if (avstream_video == nullptr) { @@ -109,6 +110,9 @@ Mux::Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const fprintf(stderr, "avformat_write_header() failed\n"); exit(1); } + for (MuxMetrics *metric : metrics) { + metric->metric_written_bytes += avctx->pb->pos; + } // Make sure the header is written before the constructor exits. avio_flush(avctx->pb); @@ -116,7 +120,12 @@ Mux::Mux(AVFormatContext *avctx, int width, int height, Codec video_codec, const Mux::~Mux() { + int64_t old_pos = avctx->pb->pos; av_write_trailer(avctx); + for (MuxMetrics *metric : metrics) { + metric->metric_written_bytes += avctx->pb->pos - old_pos; + } + if (!(avctx->oformat->flags & AVFMT_NOFILE) && !(avctx->flags & AVFMT_FLAG_CUSTOM_IO)) { avio_closep(&avctx->pb); @@ -165,11 +174,24 @@ void Mux::add_packet(const AVPacket &pkt, int64_t pts, int64_t dts) void Mux::write_packet_or_die(const AVPacket &pkt) { + for (MuxMetrics *metric : metrics) { + if (pkt.stream_index == 0) { + metric->metric_video_bytes += pkt.size; + } else if (pkt.stream_index == 1) { + metric->metric_audio_bytes += pkt.size; + } else { + assert(false); + } + } + int64_t old_pos = avctx->pb->pos; if (av_interleaved_write_frame(avctx, const_cast(&pkt)) < 0) { fprintf(stderr, "av_interleaved_write_frame() failed\n"); exit(1); } avio_flush(avctx->pb); + for (MuxMetrics *metric : metrics) { + metric->metric_written_bytes += avctx->pb->pos - old_pos; + } } void Mux::plug() @@ -194,3 +216,16 @@ void Mux::unplug() } plugged_packets.clear(); } + +void MuxMetrics::init(const vector> &labels) +{ + vector> labels_video = labels; + labels_video.emplace_back("stream", "video"); + global_metrics.add("mux_stream_bytes", labels_video, &metric_video_bytes); + + vector> labels_audio = labels; + labels_audio.emplace_back("stream", "audio"); + global_metrics.add("mux_stream_bytes", labels_audio, &metric_audio_bytes); + + global_metrics.add("mux_written_bytes", labels, &metric_written_bytes); +} diff --git a/mux.h b/mux.h index ddf97fe..c6c4421 100644 --- a/mux.h +++ b/mux.h @@ -9,11 +9,30 @@ extern "C" { } #include +#include #include #include #include +#include #include +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 { @@ -24,7 +43,9 @@ public: // 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, const std::vector &metrics); ~Mux(); void add_packet(const AVPacket &pkt, int64_t pts, int64_t dts); @@ -50,6 +71,7 @@ private: AVStream *avstream_video, *avstream_audio; std::function write_callback; + std::vector metrics; }; #endif // !defined(_MUX_H) diff --git a/quicksync_encoder.cpp b/quicksync_encoder.cpp index 8eef63d..d13cf87 100644 --- a/quicksync_encoder.cpp +++ b/quicksync_encoder.cpp @@ -70,6 +70,7 @@ namespace { // so they are outside. bool mux_metrics_inited = false; LatencyHistogram mixer_latency_histogram, qs_latency_histogram; +MuxMetrics current_file_mux_metrics, total_mux_metrics; } // namespace @@ -1827,9 +1828,17 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename) video_extradata = x264_encoder->get_global_headers(); } + if (!mux_metrics_inited) { + current_file_mux_metrics.init({{ "destination", "current_file" }}); + total_mux_metrics.init({{ "destination", "files_total" }}); + mux_metrics_inited = true; + } + current_file_mux_metrics.reset(); + AVCodecParametersWithDeleter audio_codecpar = file_audio_encoder->get_codec_parameters(); file_mux.reset(new Mux(avctx, frame_width, frame_height, Mux::CODEC_H264, video_extradata, audio_codecpar.get(), TIMEBASE, - std::bind(&DiskSpaceEstimator::report_write, disk_space_estimator, filename, _1))); + std::bind(&DiskSpaceEstimator::report_write, disk_space_estimator, filename, _1), + { ¤t_file_mux_metrics, &total_mux_metrics })); if (global_flags.x264_video_to_disk) { x264_encoder->add_mux(file_mux.get()); diff --git a/video_encoder.cpp b/video_encoder.cpp index 029652a..a622ba2 100644 --- a/video_encoder.cpp +++ b/video_encoder.cpp @@ -186,7 +186,8 @@ void VideoEncoder::open_output_stream() int time_base = global_flags.stream_coarse_timebase ? COARSE_TIMEBASE : TIMEBASE; stream_mux.reset(new Mux(avctx, width, height, video_codec, video_extradata, stream_audio_encoder->get_codec_parameters().get(), time_base, - /*write_callback=*/nullptr)); + /*write_callback=*/nullptr, { &stream_mux_metrics })); + stream_mux_metrics.init({{ "destination", "http" }}); } int VideoEncoder::write_packet2_thunk(void *opaque, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time) diff --git a/video_encoder.h b/video_encoder.h index d51399e..31c0c5f 100644 --- a/video_encoder.h +++ b/video_encoder.h @@ -20,6 +20,7 @@ extern "C" { #include } +#include "mux.h" #include "ref_counted_gl_sync.h" class AudioEncoder; @@ -94,6 +95,7 @@ private: std::unique_ptr x264_encoder; // nullptr if not using x264. std::string stream_mux_header; + MuxMetrics stream_mux_metrics; std::atomic quicksync_encoders_in_shutdown{0}; std::atomic overriding_bitrate{0}; -- 2.39.2