X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=resampling_queue.h;h=b46086df9d0954a4aebd3af0acb3937ca6e314de;hb=9e47a2f661b9d292598ef0277e507458e3dad62f;hp=cfc10481c16872bb821784916bea16c4f494d452;hpb=1cfd1241bd2d517bdd309cb2176554bf737f1937;p=nageru diff --git a/resampling_queue.h b/resampling_queue.h index cfc1048..b46086d 100644 --- a/resampling_queue.h +++ b/resampling_queue.h @@ -4,8 +4,8 @@ // Takes in samples from an input source, possibly with jitter, and outputs a fixed number // of samples every iteration. Used to a) change sample rates if needed, and b) deal with // input sources that don't have audio locked to video. For every input video -// frame, you call add_input_samples() with the pts (measured in seconds) of the video frame, -// taken to be the start point of the frame's audio. When you want to _output_ a finished +// frame, you call add_input_samples() with the received time point of the video frame, +// taken to be the _end_ point of the frame's audio. When you want to _output_ a finished // frame with audio, you get_output_samples() with the number of samples you want, and will // get exactly that number of samples back. If the input and output clocks are not in sync, // the audio will be stretched for you. (If they are _very_ out of sync, this will come through @@ -38,21 +38,30 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include #include #include +#include #include #include +#include "defs.h" + class ResamplingQueue { public: // card_num is for debugging outputs only. - ResamplingQueue(unsigned card_num, unsigned freq_in, unsigned freq_out, unsigned num_channels = 2); + ResamplingQueue(unsigned card_num, unsigned freq_in, unsigned freq_out, unsigned num_channels, double expected_delay_seconds); + + // If policy is DO_NOT_ADJUST_RATE, the resampling rate will not be changed. + // This is primarily useful if you have an extraordinary situation, such as + // dropped frames. + enum RateAdjustmentPolicy { + DO_NOT_ADJUST_RATE, + ADJUST_RATE + }; - // Note: pts is always in seconds. - void add_input_samples(double pts, const float *samples, ssize_t num_samples); - bool get_output_samples(double pts, float *samples, ssize_t num_samples); // Returns false if underrun. + void add_input_samples(std::chrono::steady_clock::time_point ts, const float *samples, ssize_t num_samples, RateAdjustmentPolicy rate_adjustment_policy); + // Returns false if underrun. + bool get_output_samples(std::chrono::steady_clock::time_point ts, float *samples, ssize_t num_samples, RateAdjustmentPolicy rate_adjustment_policy); private: void init_loop_filter(double bandwidth_hz); @@ -62,28 +71,43 @@ private: unsigned card_num; unsigned freq_in, freq_out, num_channels; - bool first_input = true, first_output = true; - double last_input_pts; // Start of last input block, in seconds. - double last_output_pts; + bool first_output = true; - ssize_t k_a0 = 0; // Total amount of samples inserted _before_ the last call to add_input_samples(). - ssize_t k_a1 = 0; // Total amount of samples inserted _after_ the last call to add_input_samples(). + struct InputPoint { + // Equivalent to t_a0 or t_a1 in the paper. + std::chrono::steady_clock::time_point ts; - ssize_t total_consumed_samples = 0; + // Number of samples that have been written to the queue (in total) + // at this time point. Equivalent to k_a0 or k_a1 in the paper. + size_t input_samples_received = 0; + + // Set to false if we should not use the timestamp from this sample + // (e.g. if it is from a dropped frame and thus bad). In particular, + // we will not use it for updateing current_estimated_freq_in. + bool good_sample = false; + }; + InputPoint a0, a1; - // Duration of last input block, in seconds. - double last_input_len; + // The current rate at which we seem to get input samples, in Hz. + // For an ideal input, identical to freq_in. + double current_estimated_freq_in; + + ssize_t total_consumed_samples = 0; // Filter state for the loop filter. double z1 = 0.0, z2 = 0.0, z3 = 0.0; // Ratio between the two frequencies. - double ratio; + const double ratio; + + // Current correction ratio. ratio * rcorr gives the true ratio, + // so values above 1.0 means to pitch down (consume input samples slower). + double rcorr = 1.0; // How much delay we are expected to have, in input samples. // If actual delay drifts too much away from this, we will start // changing the resampling ratio to compensate. - double expected_delay = OUTPUT_FREQUENCY * 0.1; // 100 ms. + const double expected_delay; // Input samples not yet fed into the resampler. // TODO: Use a circular buffer instead, for efficiency.