| @@ -27,6 +27,7 @@ · 26 unmodified lines |
| 27 | 27 | #include <float.h> |
| 28 | 28 | |
| 29 | 29 | #include "libavutil/avassert.h" |
| 30 | +#include "libavutil/channel_layout.h" |
| 30 | 31 | #include "libavutil/opt.h" |
| 31 | 32 | |
| 32 | 33 | #define MIN_FILTER_SIZE 3 |
| @@ -76,6 +77,7 @@ typedef struct DynamicAudioNormalizerContext { · 43 unmodified lines |
| 76 | 77 | |
| 77 | 78 | int channels; |
| 78 | 79 | int eof; |
| 80 | + uint64_t channels_to_filter; |
| 79 | 81 | int64_t pts; |
| 80 | 82 | |
| 81 | 83 | cqueue **gain_history_original; |
| @@ -110,6 +112,8 @@ static const AVOption dynaudnorm_options[] = { · 28 unmodified lines |
| 110 | 112 | { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS }, |
| 111 | 113 | { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS }, |
| 112 | 114 | { "t", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS }, |
| 115 | + { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS }, |
| 116 | + { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS }, |
| 113 | 117 | { NULL } |
| 114 | 118 | }; |
| 115 | 119 | |
| @@ -514,6 +518,11 @@ static inline double update_value(double new, double old, double aggressiveness) · 398 unmodified lines |
| 514 | 518 | return aggressiveness * new + (1.0 - aggressiveness) * old; |
| 515 | 519 | } |
| 516 | 520 | |
| 521 | +static inline int bypass_channel(DynamicAudioNormalizerContext *s, AVFrame *frame, int ch) |
| 522 | +{ |
| 523 | + return !(av_channel_layout_extract_channel(frame->channel_layout, ch) & s->channels_to_filter); |
| 524 | +} |
| 525 | + |
| 517 | 526 | static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *frame) |
| 518 | 527 | { |
| 519 | 528 | const double diff = 1.0 / frame->nb_samples; |
| @@ -521,6 +530,7 @@ static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *fra · 1 unmodified line |
| 521 | 530 | int c, i; |
| 522 | 531 | |
| 523 | 532 | for (c = 0; c < s->channels; c++) { |
| 533 | + const int bypass = bypass_channel(s, frame, c); |
| 524 | 534 | double *dst_ptr = (double *)frame->extended_data[c]; |
| 525 | 535 | double current_average_value = 0.0; |
| 526 | 536 | double prev_value; |
| @@ -531,7 +541,7 @@ static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *fra · 4 unmodified lines |
| 531 | 541 | prev_value = is_first_frame ? current_average_value : s->dc_correction_value[c]; |
| 532 | 542 | s->dc_correction_value[c] = is_first_frame ? current_average_value : update_value(current_average_value, s->dc_correction_value[c], 0.1); |
| 533 | 543 | |
| 534 | | − for (i = 0; i < frame->nb_samples; i++) { |
| 544 | + for (i = 0; i < frame->nb_samples && !bypass; i++) { |
| 535 | 545 | dst_ptr[i] -= fade(prev_value, s->dc_correction_value[c], i, frame->nb_samples); |
| 536 | 546 | } |
| 537 | 547 | } |
| @@ -604,6 +614,11 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame · 66 unmodified lines |
| 604 | 614 | |
| 605 | 615 | for (c = 0; c < s->channels; c++) { |
| 606 | 616 | double *const dst_ptr = (double *)frame->extended_data[c]; |
| 617 | + const int bypass = bypass_channel(s, frame, c); |
| 618 | + |
| 619 | + if (bypass) |
| 620 | + continue; |
| 621 | + |
| 607 | 622 | for (i = 0; i < frame->nb_samples; i++) { |
| 608 | 623 | const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples); |
| 609 | 624 | dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]); |
| @@ -611,19 +626,20 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame · 1 unmodified line |
| 611 | 626 | } |
| 612 | 627 | } else { |
| 613 | 628 | for (c = 0; c < s->channels; c++) { |
| 629 | + const int bypass = bypass_channel(s, frame, c); |
| 614 | 630 | const double standard_deviation = compute_frame_std_dev(s, frame, c); |
| 615 | 631 | const double current_threshold = setup_compress_thresh(FFMIN(1.0, s->compress_factor * standard_deviation)); |
| 616 | | − |
| 617 | 632 | const double prev_value = is_first_frame ? current_threshold : s->compress_threshold[c]; |
| 618 | 633 | double prev_actual_thresh, curr_actual_thresh; |
| 619 | 634 | double *dst_ptr; |
| 635 | + |
| 620 | 636 | s->compress_threshold[c] = is_first_frame ? current_threshold : update_value(current_threshold, s->compress_threshold[c], 1.0/3.0); |
| 621 | 637 | |
| 622 | 638 | prev_actual_thresh = setup_compress_thresh(prev_value); |
| 623 | 639 | curr_actual_thresh = setup_compress_thresh(s->compress_threshold[c]); |
| 624 | 640 | |
| 625 | 641 | dst_ptr = (double *)frame->extended_data[c]; |
| 626 | | − for (i = 0; i < frame->nb_samples; i++) { |
| 642 | + for (i = 0; i < frame->nb_samples && !bypass; i++) { |
| 627 | 643 | const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples); |
| 628 | 644 | dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]); |
| 629 | 645 | } |
| @@ -668,13 +684,14 @@ static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *in, · 38 unmodified lines |
| 668 | 684 | int c, i; |
| 669 | 685 | |
| 670 | 686 | for (c = 0; c < s->channels; c++) { |
| 687 | + const int bypass = bypass_channel(s, frame, c); |
| 671 | 688 | const double *src_ptr = (const double *)in->extended_data[c]; |
| 672 | 689 | double *dst_ptr = (double *)frame->extended_data[c]; |
| 673 | 690 | double current_amplification_factor; |
| 674 | 691 | |
| 675 | 692 | cqueue_dequeue(s->gain_history_smoothed[c], ¤t_amplification_factor); |
| 676 | 693 | |
| 677 | | − for (i = 0; i < frame->nb_samples && enabled; i++) { |
| 694 | + for (i = 0; i < frame->nb_samples && enabled && !bypass; i++) { |
| 678 | 695 | const double amplification_factor = fade(s->prev_amplification_factor[c], |
| 679 | 696 | current_amplification_factor, i, |
| 680 | 697 | frame->nb_samples); |