X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fx264_encoder.cpp;fp=nageru%2Fx264_encoder.cpp;h=23a1359d70fc6083307dd456a1cd53889c30c290;hb=8202dbe236c5e206989c383004f9dba116ea12bd;hp=d938393598d637365ba4d1e8e843c8878cdf311c;hpb=70e2471c1297f5ee5592918a736224841d8e4d77;p=nageru diff --git a/nageru/x264_encoder.cpp b/nageru/x264_encoder.cpp index d938393..23a1359 100644 --- a/nageru/x264_encoder.cpp +++ b/nageru/x264_encoder.cpp @@ -43,7 +43,17 @@ atomic metric_x264_output_frames_p{0}; atomic metric_x264_output_frames_b{0}; Histogram metric_x264_crf; LatencyHistogram x264_latency_histogram; -once_flag x264_metrics_inited; + +atomic metric_x264_disk_queued_frames{0}; +atomic metric_x264_disk_max_queued_frames{X264_QUEUE_LENGTH}; +atomic metric_x264_disk_dropped_frames{0}; +atomic metric_x264_disk_output_frames_i{0}; +atomic metric_x264_disk_output_frames_p{0}; +atomic metric_x264_disk_output_frames_b{0}; +Histogram metric_x264_disk_crf; +LatencyHistogram x264_disk_latency_histogram; + +once_flag x264_metrics_inited, x264_disk_metrics_inited; void update_vbv_settings(x264_param_t *param) { @@ -64,22 +74,38 @@ void update_vbv_settings(x264_param_t *param) } // namespace -X264Encoder::X264Encoder(AVOutputFormat *oformat) +X264Encoder::X264Encoder(AVOutputFormat *oformat, bool use_separate_disk_params) : wants_global_headers(oformat->flags & AVFMT_GLOBALHEADER), + use_separate_disk_params(use_separate_disk_params), dyn(load_x264_for_bit_depth(global_flags.x264_bit_depth)) { - call_once(x264_metrics_inited, [](){ - global_metrics.add("x264_queued_frames", &metric_x264_queued_frames, Metrics::TYPE_GAUGE); - global_metrics.add("x264_max_queued_frames", &metric_x264_max_queued_frames, Metrics::TYPE_GAUGE); - global_metrics.add("x264_dropped_frames", &metric_x264_dropped_frames); - global_metrics.add("x264_output_frames", {{ "type", "i" }}, &metric_x264_output_frames_i); - global_metrics.add("x264_output_frames", {{ "type", "p" }}, &metric_x264_output_frames_p); - global_metrics.add("x264_output_frames", {{ "type", "b" }}, &metric_x264_output_frames_b); - - metric_x264_crf.init_uniform(50); - global_metrics.add("x264_crf", &metric_x264_crf); - x264_latency_histogram.init("x264"); - }); + if (use_separate_disk_params) { + call_once(x264_disk_metrics_inited, []{ + global_metrics.add("x264_queued_frames", {{ "encode", "separate_disk" }}, &metric_x264_disk_queued_frames, Metrics::TYPE_GAUGE); + global_metrics.add("x264_max_queued_frames", {{ "encode", "separate_disk" }}, &metric_x264_disk_max_queued_frames, Metrics::TYPE_GAUGE); + global_metrics.add("x264_dropped_frames", {{ "encode", "separate_disk" }}, &metric_x264_disk_dropped_frames); + global_metrics.add("x264_output_frames", {{ "encode", "separate_disk" }, { "type", "i" }}, &metric_x264_disk_output_frames_i); + global_metrics.add("x264_output_frames", {{ "encode", "separate_disk" }, { "type", "p" }}, &metric_x264_disk_output_frames_p); + global_metrics.add("x264_output_frames", {{ "encode", "separate_disk" }, { "type", "b" }}, &metric_x264_disk_output_frames_b); + + metric_x264_disk_crf.init_uniform(50); + global_metrics.add("x264_crf", {{ "encode", "separate_disk" }}, &metric_x264_disk_crf); + x264_disk_latency_histogram.init("x264_disk"); + }); + } else { + call_once(use_separate_disk_params ? x264_disk_metrics_inited : x264_metrics_inited, []{ + global_metrics.add("x264_queued_frames", {{ "encode", "regular" }}, &metric_x264_queued_frames, Metrics::TYPE_GAUGE); + global_metrics.add("x264_max_queued_frames", {{ "encode", "regular" }}, &metric_x264_max_queued_frames, Metrics::TYPE_GAUGE); + global_metrics.add("x264_dropped_frames", {{ "encode", "regular" }}, &metric_x264_dropped_frames); + global_metrics.add("x264_output_frames", {{ "encode", "regular" }, { "type", "i" }}, &metric_x264_output_frames_i); + global_metrics.add("x264_output_frames", {{ "encode", "regular" }, { "type", "p" }}, &metric_x264_output_frames_p); + global_metrics.add("x264_output_frames", {{ "encode", "regular" }, { "type", "b" }}, &metric_x264_output_frames_b); + + metric_x264_crf.init_uniform(50); + global_metrics.add("x264_crf", {{ "encode", "regular" }}, &metric_x264_crf); + x264_latency_histogram.init("x264"); + }); + } size_t bytes_per_pixel = global_flags.x264_bit_depth > 8 ? 2 : 1; frame_pool.reset(new uint8_t[global_flags.width * global_flags.height * 2 * bytes_per_pixel * X264_QUEUE_LENGTH]); @@ -112,8 +138,13 @@ void X264Encoder::add_frame(int64_t pts, int64_t duration, YCbCrLumaCoefficients { lock_guard lock(mu); if (free_frames.empty()) { - fprintf(stderr, "WARNING: x264 queue full, dropping frame with pts %" PRId64 "\n", pts); - ++metric_x264_dropped_frames; + if (use_separate_disk_params) { + fprintf(stderr, "WARNING: x264 queue full (disk encoder), dropping frame with pts %" PRId64 "\n", pts); + ++metric_x264_disk_dropped_frames; + } else { + fprintf(stderr, "WARNING: x264 queue full, dropping frame with pts %" PRId64 "\n", pts); + ++metric_x264_dropped_frames; + } return; } @@ -128,14 +159,22 @@ void X264Encoder::add_frame(int64_t pts, int64_t duration, YCbCrLumaCoefficients lock_guard lock(mu); queued_frames.push(qf); queued_frames_nonempty.notify_all(); - metric_x264_queued_frames = queued_frames.size(); + if (use_separate_disk_params) { + metric_x264_disk_queued_frames = queued_frames.size(); + } else { + metric_x264_queued_frames = queued_frames.size(); + } } } void X264Encoder::init_x264() { x264_param_t param; - dyn.x264_param_default_preset(¶m, global_flags.x264_preset.c_str(), global_flags.x264_tune.c_str()); + if (use_separate_disk_params) { + dyn.x264_param_default_preset(¶m, global_flags.x264_separate_disk_preset.c_str(), global_flags.x264_separate_disk_tune.c_str()); + } else { + dyn.x264_param_default_preset(¶m, global_flags.x264_preset.c_str(), global_flags.x264_tune.c_str()); + } param.i_width = global_flags.width; param.i_height = global_flags.height; @@ -147,7 +186,7 @@ void X264Encoder::init_x264() param.i_timebase_num = 1; param.i_timebase_den = TIMEBASE; param.i_keyint_max = 50; // About one second. - if (global_flags.x264_speedcontrol) { + if (!use_separate_disk_params && global_flags.x264_speedcontrol) { param.i_frame_reference = 16; // Because speedcontrol is never allowed to change this above what we set at start. } #if X264_BUILD >= 153 @@ -165,14 +204,18 @@ void X264Encoder::init_x264() param.vui.i_colmatrix = 6; // BT.601/SMPTE 170M. } - if (!isinf(global_flags.x264_crf)) { + const double crf = use_separate_disk_params ? global_flags.x264_separate_disk_crf : global_flags.x264_crf; + const int bitrate = use_separate_disk_params ? global_flags.x264_separate_disk_bitrate : global_flags.x264_bitrate; + if (!isinf(crf)) { param.rc.i_rc_method = X264_RC_CRF; - param.rc.f_rf_constant = global_flags.x264_crf; + param.rc.f_rf_constant = crf; } else { param.rc.i_rc_method = X264_RC_ABR; - param.rc.i_bitrate = global_flags.x264_bitrate; + param.rc.i_bitrate = bitrate; + } + if (!use_separate_disk_params) { + update_vbv_settings(¶m); } - update_vbv_settings(¶m); if (param.rc.i_vbv_max_bitrate > 0) { // If the user wants VBV control to cap the max rate, it is // also reasonable to assume that they are fine with the stream @@ -205,7 +248,8 @@ void X264Encoder::init_x264() // be on the safe side. Shouldn't affect quality in any meaningful way. param.rc.i_qp_min = 5; - for (const string &str : global_flags.x264_extra_param) { + const vector &extra_param = use_separate_disk_params ? global_flags.x264_separate_disk_extra_param : global_flags.x264_extra_param; + for (const string &str : extra_param) { const size_t pos = str.find(','); if (pos == string::npos) { if (dyn.x264_param_parse(¶m, str.c_str(), nullptr) != 0) { @@ -235,7 +279,7 @@ void X264Encoder::init_x264() abort(); } - if (global_flags.x264_speedcontrol) { + if (!use_separate_disk_params && global_flags.x264_speedcontrol) { speed_control.reset(new X264SpeedControl(x264, /*f_speed=*/1.0f, X264_QUEUE_LENGTH, /*f_buffer_init=*/1.0f)); } @@ -284,7 +328,11 @@ void X264Encoder::encoder_thread_func() qf.data = nullptr; } - metric_x264_queued_frames = queued_frames.size(); + if (use_separate_disk_params) { + metric_x264_disk_queued_frames = queued_frames.size(); + } else { + metric_x264_queued_frames = queued_frames.size(); + } frames_left = !queued_frames.empty(); } @@ -360,15 +408,27 @@ void X264Encoder::encode_frame(X264Encoder::QueuedFrame qf) if (num_nal == 0) return; - if (IS_X264_TYPE_I(pic.i_type)) { - ++metric_x264_output_frames_i; - } else if (IS_X264_TYPE_B(pic.i_type)) { - ++metric_x264_output_frames_b; + if (use_separate_disk_params) { + if (IS_X264_TYPE_I(pic.i_type)) { + ++metric_x264_disk_output_frames_i; + } else if (IS_X264_TYPE_B(pic.i_type)) { + ++metric_x264_disk_output_frames_b; + } else { + ++metric_x264_disk_output_frames_p; + } + + metric_x264_disk_crf.count_event(pic.prop.f_crf_avg); } else { - ++metric_x264_output_frames_p; - } + if (IS_X264_TYPE_I(pic.i_type)) { + ++metric_x264_output_frames_i; + } else if (IS_X264_TYPE_B(pic.i_type)) { + ++metric_x264_output_frames_b; + } else { + ++metric_x264_output_frames_p; + } - metric_x264_crf.count_event(pic.prop.f_crf_avg); + metric_x264_crf.count_event(pic.prop.f_crf_avg); + } if (frames_being_encoded.count(pic.i_pts)) { ReceivedTimestamps received_ts = frames_being_encoded[pic.i_pts];