From: Steinar H. Gunderson Date: Fri, 22 Jul 2016 17:54:37 +0000 (+0200) Subject: Add a menu option to change x264 video bitrate while running. X-Git-Tag: 1.3.2~3 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=b85c1986b7ea63534899e2eb589f9e0888d5ccda Add a menu option to change x264 video bitrate while running. --- diff --git a/mainwindow.cpp b/mainwindow.cpp index 627d558..4b8eb51 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include "aboutdialog.h" +#include "flags.h" #include "glwidget.h" #include "lrameter.h" #include "mixer.h" @@ -61,7 +63,13 @@ MainWindow::MainWindow() // The menus. connect(ui->cut_action, &QAction::triggered, this, &MainWindow::cut_triggered); connect(ui->exit_action, &QAction::triggered, this, &MainWindow::exit_triggered); - connect(ui->about_action, &QAction::triggered, this, &MainWindow::about_triggered), + connect(ui->about_action, &QAction::triggered, this, &MainWindow::about_triggered); + + if (global_flags.x264_video_to_http) { + connect(ui->x264_bitrate_action, &QAction::triggered, this, &MainWindow::x264_bitrate_triggered); + } else { + ui->x264_bitrate_action->setEnabled(false); + } // Hook up the transition buttons. (Keyboard shortcuts are set in set_transition_names().) // TODO: Make them dynamic. @@ -187,6 +195,16 @@ void MainWindow::cut_triggered() global_mixer->schedule_cut(); } +void MainWindow::x264_bitrate_triggered() +{ + bool ok; + int new_bitrate = QInputDialog::getInt(this, "Change x264 bitrate", "Choose new bitrate for x264 HTTP output (from 100–100,000 kbit/sec):", global_flags.x264_bitrate, /*min=*/100, /*max=*/100000, /*step=*/100, &ok); + if (ok && new_bitrate >= 100 && new_bitrate <= 100000) { + global_flags.x264_bitrate = new_bitrate; + global_mixer->change_x264_bitrate(new_bitrate); + } +} + void MainWindow::exit_triggered() { close(); diff --git a/mainwindow.h b/mainwindow.h index e6d0880..8110176 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -33,6 +33,7 @@ public: public slots: void cut_triggered(); + void x264_bitrate_triggered(); void exit_triggered(); void about_triggered(); void transition_clicked(int transition_number); diff --git a/mixer.h b/mixer.h index 1d6d030..21b2255 100644 --- a/mixer.h +++ b/mixer.h @@ -387,6 +387,10 @@ public: cards[card_index].capture->set_audio_input(input); } + void change_x264_bitrate(unsigned rate_kbit) { + video_encoder->change_x264_bitrate(rate_kbit); + } + private: void configure_card(unsigned card_index, CaptureInterface *capture, bool is_fake_capture); void bm_frame(unsigned card_index, uint16_t timecode, diff --git a/ui_mainwindow.ui b/ui_mainwindow.ui index 2d7031c..8c92311 100644 --- a/ui_mainwindow.ui +++ b/ui_mainwindow.ui @@ -878,7 +878,7 @@ 0 0 1089 - 19 + 23 @@ -886,6 +886,7 @@ &Video + @@ -912,6 +913,11 @@ &About Nageru… + + + Change &x264 bitrate… + + diff --git a/video_encoder.cpp b/video_encoder.cpp index 07bb1c9..dbb2aa7 100644 --- a/video_encoder.cpp +++ b/video_encoder.cpp @@ -96,6 +96,11 @@ void VideoEncoder::do_cut(int frame) quicksync_encoder->set_stream_mux(stream_mux.get()); } +void VideoEncoder::change_x264_bitrate(unsigned rate_kbit) +{ + x264_encoder->change_bitrate(rate_kbit); +} + void VideoEncoder::add_audio(int64_t pts, std::vector audio) { lock_guard lock(qs_mu); diff --git a/video_encoder.h b/video_encoder.h index fc3a570..fd16ac8 100644 --- a/video_encoder.h +++ b/video_encoder.h @@ -37,6 +37,8 @@ public: // Does a cut of the disk stream immediately ("frame" is used for the filename only). void do_cut(int frame); + void change_x264_bitrate(unsigned rate_kbit); + private: void open_output_stream(); static int write_packet2_thunk(void *opaque, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time); diff --git a/x264_encoder.cpp b/x264_encoder.cpp index 7be454c..756d673 100644 --- a/x264_encoder.cpp +++ b/x264_encoder.cpp @@ -14,6 +14,24 @@ extern "C" { using namespace std; +namespace { + +void update_vbv_settings(x264_param_t *param) +{ + if (global_flags.x264_vbv_buffer_size < 0) { + param->rc.i_vbv_buffer_size = param->rc.i_bitrate; // One-second VBV. + } else { + param->rc.i_vbv_buffer_size = global_flags.x264_vbv_buffer_size; + } + if (global_flags.x264_vbv_max_bitrate < 0) { + param->rc.i_vbv_max_bitrate = param->rc.i_bitrate; // CBR. + } else { + param->rc.i_vbv_max_bitrate = global_flags.x264_vbv_max_bitrate; + } +} + +} // namespace + X264Encoder::X264Encoder(AVOutputFormat *oformat) : wants_global_headers(oformat->flags & AVFMT_GLOBALHEADER) { @@ -83,16 +101,7 @@ void X264Encoder::init_x264() param.rc.i_rc_method = X264_RC_ABR; param.rc.i_bitrate = global_flags.x264_bitrate; - if (global_flags.x264_vbv_buffer_size < 0) { - param.rc.i_vbv_buffer_size = param.rc.i_bitrate; // One-second VBV. - } else { - param.rc.i_vbv_buffer_size = global_flags.x264_vbv_buffer_size; - } - if (global_flags.x264_vbv_max_bitrate < 0) { - param.rc.i_vbv_max_bitrate = param.rc.i_bitrate; // CBR. - } else { - param.rc.i_vbv_max_bitrate = global_flags.x264_vbv_max_bitrate; - } + 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 @@ -234,6 +243,17 @@ void X264Encoder::encode_frame(X264Encoder::QueuedFrame qf) input_pic = &pic; } + // See if we have a new bitrate to change to. + unsigned new_rate = new_bitrate_kbit.exchange(0); // Read and clear. + if (new_rate != 0) { + x264_param_t param; + x264_encoder_parameters(x264, ¶m); + param.rc.i_bitrate = new_rate; + update_vbv_settings(¶m); + x264_encoder_reconfig(x264, ¶m); + printf("changing rate to %u\n", new_rate); + } + if (speed_control) { speed_control->before_frame(float(free_frames.size()) / X264_QUEUE_LENGTH, X264_QUEUE_LENGTH, 1e6 * qf.duration / TIMEBASE); } diff --git a/x264_encoder.h b/x264_encoder.h index ef118c6..bb9f1dc 100644 --- a/x264_encoder.h +++ b/x264_encoder.h @@ -50,6 +50,10 @@ public: 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; @@ -75,6 +79,8 @@ private: 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;