diff options
Diffstat (limited to 'src/filter/volume_filter_plugin.c')
-rw-r--r-- | src/filter/volume_filter_plugin.c | 101 |
1 files changed, 55 insertions, 46 deletions
diff --git a/src/filter/volume_filter_plugin.c b/src/filter/volume_filter_plugin.c index e52c0a46..27276998 100644 --- a/src/filter/volume_filter_plugin.c +++ b/src/filter/volume_filter_plugin.c @@ -23,7 +23,6 @@ #include "filter_internal.h" #include "filter_registry.h" #include "conf.h" -#include "pcm_buffer.h" #include "pcm_volume.h" #include "audio_format.h" #include "player_control.h" @@ -31,6 +30,10 @@ #include <assert.h> #include <string.h> +#include <libavutil/channel_layout.h> +#include <libavutil/frame.h> +#include <libavutil/samplefmt.h> + struct volume_filter { struct filter filter; @@ -40,8 +43,6 @@ struct volume_filter { unsigned volume; struct audio_format audio_format; - - struct pcm_buffer buffer; }; static inline GQuark @@ -75,54 +76,63 @@ volume_filter_open(struct filter *_filter, struct audio_format *audio_format, struct volume_filter *filter = (struct volume_filter *)_filter; filter->audio_format = *audio_format; - pcm_buffer_init(&filter->buffer); return &filter->audio_format; } -static void -volume_filter_close(struct filter *_filter) -{ - struct volume_filter *filter = (struct volume_filter *)_filter; - - pcm_buffer_deinit(&filter->buffer); -} - -static const void * -volume_filter_filter(struct filter *_filter, const void *src, size_t src_size, - size_t *dest_size_r, GError **error_r) +static AVFrame *volume_filter_filter(struct filter *_filter, AVFrame *src) { struct volume_filter *filter = (struct volume_filter *)_filter; - bool success; - void *dest; - - *dest_size_r = src_size; - - if (filter->volume >= PCM_VOLUME_1) - /* optimized special case: 100% volume = no-op */ - return src; - - dest = pcm_buffer_get(&filter->buffer, src_size); - - if (filter->volume <= 0) { - /* optimized special case: 0% volume = memset(0) */ - /* XXX is this valid for all sample formats? What - about floating point? */ - memset(dest, 0, src_size); - return dest; - } - - memcpy(dest, src, src_size); - - success = pcm_volume(dest, src_size, filter->audio_format.format, - filter->volume); - if (!success) { - g_set_error(error_r, volume_quark(), 0, - "pcm_volume() has failed"); - return NULL; - } - - return dest; + int planar = av_sample_fmt_is_planar(src->format); + int planes = planar ? av_get_channel_layout_nb_channels(src->channel_layout) : 1; + int ret, i; + + /* optimized special case: 100% volume = no-op */ + if (filter->volume == PCM_VOLUME_1) + return src; + + /* optimized special case: 0% volume = memset(0) */ + if (filter->volume <= 0) { + AVFrame *dst = av_frame_alloc(); + if (!dst) { + av_frame_free(&src); + return NULL; + } + + dst->nb_samples = src->nb_samples; + dst->format = src->format; + dst->channel_layout = src->channel_layout; + av_frame_copy_props(dst, src); + av_frame_free(&src); + + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) + return NULL; + + av_samples_set_silence(dst->extended_data, 0, dst->nb_samples, + av_get_channel_layout_nb_channels(dst->channel_layout), + dst->format); + return dst; + } + + ret = av_frame_make_writable(src); + if (ret < 0) { + av_frame_free(&src); + return NULL; + } + + for (i = 0; i < planes; i++) { + ret = pcm_volume(src->extended_data[i], src->linesize[0], + av_get_packed_sample_fmt(filter->audio_format.format), + filter->volume); + if (!ret) { + g_warning("pcm_volume() has failed"); + av_frame_free(&src); + return NULL; + } + } + + return src; } const struct filter_plugin volume_filter_plugin = { @@ -130,7 +140,6 @@ const struct filter_plugin volume_filter_plugin = { .init = volume_filter_init, .finish = volume_filter_finish, .open = volume_filter_open, - .close = volume_filter_close, .filter = volume_filter_filter, }; |