2013-03-09 08:30:26 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
|
|
|
|
* Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
|
|
|
|
*
|
2013-10-23 17:05:47 +00:00
|
|
|
* Based on Michael Niedermayer's lavcresample.
|
2013-03-09 08:30:26 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
|
|
|
* mpv is free software; you can redistribute it and/or modify
|
2013-03-09 08:30:26 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2013-03-09 08:30:26 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
2015-04-13 07:36:54 +00:00
|
|
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2013-03-09 08:30:26 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <inttypes.h>
|
2015-03-02 18:09:44 +00:00
|
|
|
#include <math.h>
|
2013-11-10 22:17:04 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
#include <libavutil/opt.h>
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
#include <libavutil/samplefmt.h>
|
2015-09-04 20:16:13 +00:00
|
|
|
#include <libavutil/channel_layout.h>
|
2013-03-09 08:30:26 +00:00
|
|
|
#include <libavutil/mathematics.h>
|
|
|
|
|
2015-03-02 18:09:44 +00:00
|
|
|
#include "common/common.h"
|
2013-03-09 08:30:26 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_LIBAVRESAMPLE
|
2013-03-09 08:30:26 +00:00
|
|
|
#include <libavresample/avresample.h>
|
2013-07-16 11:28:28 +00:00
|
|
|
#elif HAVE_LIBSWRESAMPLE
|
2013-03-09 08:30:26 +00:00
|
|
|
#include <libswresample/swresample.h>
|
|
|
|
#define AVAudioResampleContext SwrContext
|
|
|
|
#define avresample_alloc_context swr_alloc
|
|
|
|
#define avresample_open swr_init
|
|
|
|
#define avresample_close(x) do { } while(0)
|
2013-10-19 11:18:25 +00:00
|
|
|
#define avresample_free swr_free
|
2013-03-09 08:30:26 +00:00
|
|
|
#define avresample_available(x) 0
|
|
|
|
#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
|
|
|
|
swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
|
2013-04-05 22:56:01 +00:00
|
|
|
#define avresample_set_channel_mapping swr_set_channel_mapping
|
2015-10-07 19:43:05 +00:00
|
|
|
#define avresample_set_compensation swr_set_compensation
|
2013-03-09 08:30:26 +00:00
|
|
|
#else
|
2013-07-16 11:28:28 +00:00
|
|
|
#error "config.h broken or no resampler found"
|
2013-03-09 08:30:26 +00:00
|
|
|
#endif
|
|
|
|
|
2014-08-02 01:12:09 +00:00
|
|
|
#include "common/av_common.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
2013-03-09 08:30:26 +00:00
|
|
|
#include "audio/filter/af.h"
|
2013-03-23 12:01:44 +00:00
|
|
|
#include "audio/fmt-conversion.h"
|
2015-06-17 11:36:40 +00:00
|
|
|
#include "osdep/endian.h"
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
struct af_resample_opts {
|
|
|
|
int filter_size;
|
|
|
|
int phase_shift;
|
|
|
|
int linear;
|
|
|
|
double cutoff;
|
2015-09-08 20:04:45 +00:00
|
|
|
int normalize;
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct af_resample {
|
2013-03-29 21:29:13 +00:00
|
|
|
int allow_detach;
|
2014-08-02 01:12:09 +00:00
|
|
|
char **avopts;
|
2015-03-02 18:09:44 +00:00
|
|
|
double playback_speed;
|
2013-03-09 08:30:26 +00:00
|
|
|
struct AVAudioResampleContext *avrctx;
|
2015-05-04 21:59:20 +00:00
|
|
|
struct mp_audio avrctx_fmt; // output format of avrctx
|
2015-06-12 15:53:23 +00:00
|
|
|
struct mp_audio pool_fmt; // format used to allocate frames for avrctx output
|
2015-06-16 20:38:37 +00:00
|
|
|
struct mp_audio pre_out_fmt; // format before final conversion (S24)
|
2013-04-05 22:56:01 +00:00
|
|
|
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
|
2013-03-09 08:30:26 +00:00
|
|
|
struct af_resample_opts opts; // opts requested by the user
|
2013-04-05 22:56:01 +00:00
|
|
|
// At least libswresample keeps a pointer around for this:
|
|
|
|
int reorder_in[MP_NUM_CHANNELS];
|
|
|
|
int reorder_out[MP_NUM_CHANNELS];
|
2015-01-14 21:15:31 +00:00
|
|
|
struct mp_audio_pool *reorder_buffer;
|
2015-09-08 20:21:19 +00:00
|
|
|
|
|
|
|
int in_rate_af; // filter input sample rate
|
|
|
|
int in_rate; // actual rate (used by lavr), adjusted for playback speed
|
|
|
|
int in_format;
|
|
|
|
struct mp_chmap in_channels;
|
|
|
|
int out_rate;
|
|
|
|
int out_format;
|
|
|
|
struct mp_chmap out_channels;
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_LIBAVRESAMPLE
|
2015-06-04 18:08:12 +00:00
|
|
|
static double get_delay(struct af_resample *s)
|
2013-03-09 08:30:26 +00:00
|
|
|
{
|
2015-09-08 20:21:19 +00:00
|
|
|
return avresample_get_delay(s->avrctx) / (double)s->in_rate +
|
|
|
|
avresample_available(s->avrctx) / (double)s->out_rate;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
2013-11-18 13:18:37 +00:00
|
|
|
static void drop_all_output(struct af_resample *s)
|
|
|
|
{
|
|
|
|
while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
|
|
|
|
}
|
2015-06-02 20:20:04 +00:00
|
|
|
static int get_out_samples(struct af_resample *s, int in_samples)
|
2015-03-02 18:09:44 +00:00
|
|
|
{
|
2015-06-02 20:20:04 +00:00
|
|
|
return avresample_get_out_samples(s->avrctx, in_samples);
|
2015-03-02 18:09:44 +00:00
|
|
|
}
|
2013-03-09 08:30:26 +00:00
|
|
|
#else
|
2015-06-04 18:08:12 +00:00
|
|
|
static double get_delay(struct af_resample *s)
|
2013-03-09 08:30:26 +00:00
|
|
|
{
|
2015-09-08 20:21:19 +00:00
|
|
|
int64_t base = s->in_rate * (int64_t)s->out_rate;
|
2015-06-04 18:08:12 +00:00
|
|
|
return swr_get_delay(s->avrctx, base) / (double)base;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
2013-11-18 13:18:37 +00:00
|
|
|
static void drop_all_output(struct af_resample *s)
|
|
|
|
{
|
|
|
|
while (swr_drop_output(s->avrctx, 1000) > 0) {}
|
|
|
|
}
|
2015-06-02 20:20:04 +00:00
|
|
|
static int get_out_samples(struct af_resample *s, int in_samples)
|
2015-03-02 18:09:44 +00:00
|
|
|
{
|
2015-06-04 17:22:45 +00:00
|
|
|
#if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2
|
|
|
|
return swr_get_out_samples(s->avrctx, in_samples);
|
|
|
|
#else
|
2015-09-08 20:21:19 +00:00
|
|
|
return av_rescale_rnd(in_samples, s->out_rate, s->in_rate, AV_ROUND_UP)
|
|
|
|
+ swr_get_delay(s->avrctx, s->out_rate);
|
2015-06-04 17:22:45 +00:00
|
|
|
#endif
|
2015-03-02 18:09:44 +00:00
|
|
|
}
|
2013-03-09 08:30:26 +00:00
|
|
|
#endif
|
|
|
|
|
2015-06-22 15:05:42 +00:00
|
|
|
static void close_lavrr(struct af_instance *af)
|
|
|
|
{
|
|
|
|
struct af_resample *s = af->priv;
|
|
|
|
|
|
|
|
if (s->avrctx)
|
|
|
|
avresample_close(s->avrctx);
|
|
|
|
avresample_free(&s->avrctx);
|
|
|
|
if (s->avrctx_out)
|
|
|
|
avresample_close(s->avrctx_out);
|
|
|
|
avresample_free(&s->avrctx_out);
|
|
|
|
}
|
|
|
|
|
2015-03-02 18:09:44 +00:00
|
|
|
static int resample_frame(struct AVAudioResampleContext *r,
|
|
|
|
struct mp_audio *out, struct mp_audio *in)
|
|
|
|
{
|
|
|
|
return avresample_convert(r,
|
|
|
|
out ? (uint8_t **)out->planes : NULL,
|
|
|
|
out ? mp_audio_get_allocated_size(out) : 0,
|
|
|
|
out ? out->samples : 0,
|
|
|
|
in ? (uint8_t **)in->planes : NULL,
|
|
|
|
in ? mp_audio_get_allocated_size(in) : 0,
|
|
|
|
in ? in->samples : 0);
|
|
|
|
}
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
static double af_resample_default_cutoff(int filter_size)
|
|
|
|
{
|
|
|
|
return FFMAX(1.0 - 6.5 / (filter_size + 8), 0.80);
|
|
|
|
}
|
|
|
|
|
2015-03-02 18:09:44 +00:00
|
|
|
static int rate_from_speed(int rate, double speed)
|
|
|
|
{
|
|
|
|
return lrint(rate * speed);
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:00:26 +00:00
|
|
|
// Return the format libavresample should convert to, given the final output
|
|
|
|
// format mp_format. In some cases (S24) we perform an extra conversion step,
|
|
|
|
// and signal here what exactly libavresample should output. It will be the
|
|
|
|
// input to the final conversion to mp_format.
|
2015-06-16 20:38:37 +00:00
|
|
|
static int check_output_conversion(int mp_format)
|
|
|
|
{
|
|
|
|
if (mp_format == AF_FORMAT_S24)
|
|
|
|
return AV_SAMPLE_FMT_S32;
|
|
|
|
return af_to_avformat(mp_format);
|
|
|
|
}
|
|
|
|
|
2015-06-22 13:02:03 +00:00
|
|
|
bool af_lavrresample_test_conversion(int src_format, int dst_format)
|
|
|
|
{
|
|
|
|
return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
|
|
|
|
check_output_conversion(dst_format) != AV_SAMPLE_FMT_NONE;
|
|
|
|
}
|
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
// mp_chmap_get_reorder() performs:
|
|
|
|
// to->speaker[n] = from->speaker[src[n]]
|
|
|
|
// but libavresample does:
|
|
|
|
// to->speaker[dst[n]] = from->speaker[n]
|
|
|
|
static void transpose_order(int *map, int num)
|
|
|
|
{
|
|
|
|
int nmap[MP_NUM_CHANNELS] = {0};
|
|
|
|
for (int n = 0; n < num; n++) {
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
|
|
if (map[n] == i)
|
|
|
|
nmap[i] = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(map, nmap, sizeof(nmap));
|
|
|
|
}
|
|
|
|
|
2013-11-09 22:20:58 +00:00
|
|
|
static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
|
2015-07-19 20:50:08 +00:00
|
|
|
struct mp_audio *out, bool verbose)
|
2013-11-09 22:20:58 +00:00
|
|
|
{
|
|
|
|
struct af_resample *s = af->priv;
|
|
|
|
|
2015-06-22 15:05:42 +00:00
|
|
|
close_lavrr(af);
|
|
|
|
|
|
|
|
s->avrctx = avresample_alloc_context();
|
|
|
|
s->avrctx_out = avresample_alloc_context();
|
|
|
|
if (!s->avrctx || !s->avrctx_out)
|
|
|
|
goto error;
|
2015-03-02 18:09:44 +00:00
|
|
|
|
2013-11-09 22:20:58 +00:00
|
|
|
enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
|
2015-06-16 20:38:37 +00:00
|
|
|
enum AVSampleFormat out_samplefmt = check_output_conversion(out->format);
|
|
|
|
enum AVSampleFormat out_samplefmtp = av_get_planar_sample_fmt(out_samplefmt);
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
if (in_samplefmt == AV_SAMPLE_FMT_NONE ||
|
|
|
|
out_samplefmt == AV_SAMPLE_FMT_NONE ||
|
|
|
|
out_samplefmtp == AV_SAMPLE_FMT_NONE)
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-09-08 20:21:19 +00:00
|
|
|
s->out_rate = out->rate;
|
|
|
|
s->in_rate_af = in->rate;
|
|
|
|
s->in_rate = rate_from_speed(in->rate, s->playback_speed);
|
|
|
|
s->out_format = out->format;
|
|
|
|
s->in_format = in->format;
|
|
|
|
s->out_channels= out->channels;
|
|
|
|
s->in_channels = in->channels;
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-09-08 20:21:19 +00:00
|
|
|
av_opt_set_int(s->avrctx, "filter_size", s->opts.filter_size, 0);
|
|
|
|
av_opt_set_int(s->avrctx, "phase_shift", s->opts.phase_shift, 0);
|
|
|
|
av_opt_set_int(s->avrctx, "linear_interp", s->opts.linear, 0);
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-09-08 20:21:19 +00:00
|
|
|
av_opt_set_double(s->avrctx, "cutoff", s->opts.cutoff, 0);
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-04-01 22:42:54 +00:00
|
|
|
#if HAVE_LIBSWRESAMPLE
|
2015-09-08 20:04:45 +00:00
|
|
|
av_opt_set_double(s->avrctx, "rematrix_maxval", s->opts.normalize ? 1 : 1000, 0);
|
|
|
|
#else
|
|
|
|
av_opt_set_int(s->avrctx, "normalize_mix_level", s->opts.normalize, 0);
|
2015-04-01 22:42:54 +00:00
|
|
|
#endif
|
|
|
|
|
2014-08-02 01:12:09 +00:00
|
|
|
if (mp_set_avopts(af->log, s->avrctx, s->avopts) < 0)
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2013-11-09 22:20:58 +00:00
|
|
|
|
|
|
|
struct mp_chmap map_in = in->channels;
|
|
|
|
struct mp_chmap map_out = out->channels;
|
|
|
|
|
|
|
|
// Try not to do any remixing if at least one is "unknown".
|
|
|
|
if (mp_chmap_is_unknown(&map_in) || mp_chmap_is_unknown(&map_out)) {
|
|
|
|
mp_chmap_set_unknown(&map_in, map_in.num);
|
|
|
|
mp_chmap_set_unknown(&map_out, map_out.num);
|
|
|
|
}
|
|
|
|
|
|
|
|
// unchecked: don't take any channel reordering into account
|
|
|
|
uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&map_in);
|
|
|
|
uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&map_out);
|
|
|
|
|
2015-06-30 20:39:57 +00:00
|
|
|
struct mp_chmap in_lavc, out_lavc;
|
2013-11-09 22:20:58 +00:00
|
|
|
mp_chmap_from_lavc(&in_lavc, in_ch_layout);
|
2015-06-30 20:39:57 +00:00
|
|
|
mp_chmap_from_lavc(&out_lavc, out_ch_layout);
|
|
|
|
|
2015-11-04 12:44:01 +00:00
|
|
|
if (verbose && !mp_chmap_equals(&in_lavc, &out_lavc)) {
|
|
|
|
MP_VERBOSE(af, "Remix: %s -> %s\n", mp_chmap_to_str(&in_lavc),
|
|
|
|
mp_chmap_to_str(&out_lavc));
|
|
|
|
}
|
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
if (in_lavc.num != map_in.num) {
|
|
|
|
// For handling NA channels, we would have to add a planarization step.
|
|
|
|
MP_FATAL(af, "Unsupported channel remapping.\n");
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2015-05-04 21:59:20 +00:00
|
|
|
}
|
|
|
|
|
2013-11-09 22:20:58 +00:00
|
|
|
mp_chmap_get_reorder(s->reorder_in, &map_in, &in_lavc);
|
2015-05-04 21:59:20 +00:00
|
|
|
transpose_order(s->reorder_in, map_in.num);
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
if (mp_chmap_equals(&out_lavc, &map_out)) {
|
|
|
|
// No intermediate step required - output new format directly.
|
|
|
|
out_samplefmtp = out_samplefmt;
|
|
|
|
} else {
|
|
|
|
// Verify that we really just reorder and/or insert NA channels.
|
|
|
|
struct mp_chmap withna = out_lavc;
|
|
|
|
mp_chmap_fill_na(&withna, map_out.num);
|
|
|
|
if (withna.num != map_out.num)
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2015-05-04 21:59:20 +00:00
|
|
|
}
|
2015-06-16 19:40:29 +00:00
|
|
|
mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
|
2015-05-04 21:59:20 +00:00
|
|
|
|
|
|
|
s->avrctx_fmt = *out;
|
|
|
|
mp_audio_set_channels(&s->avrctx_fmt, &out_lavc);
|
|
|
|
mp_audio_set_format(&s->avrctx_fmt, af_from_avformat(out_samplefmtp));
|
2013-11-09 22:20:58 +00:00
|
|
|
|
2015-06-16 20:38:37 +00:00
|
|
|
s->pre_out_fmt = *out;
|
|
|
|
mp_audio_set_format(&s->pre_out_fmt, af_from_avformat(out_samplefmt));
|
|
|
|
|
2015-06-12 15:53:23 +00:00
|
|
|
// If there are NA channels, the final output will have more channels than
|
|
|
|
// the avrctx output. Also, avrctx will output planar (out_samplefmtp was
|
|
|
|
// not overwritten). Allocate the output frame with more channels, so the
|
|
|
|
// NA channels can be trivially added.
|
|
|
|
s->pool_fmt = s->avrctx_fmt;
|
|
|
|
if (map_out.num > out_lavc.num)
|
|
|
|
mp_audio_set_channels(&s->pool_fmt, &map_out);
|
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
// Real conversion; output is input to avrctx_out.
|
|
|
|
av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
|
|
|
|
av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
|
2015-09-08 20:21:19 +00:00
|
|
|
av_opt_set_int(s->avrctx, "in_sample_rate", s->in_rate, 0);
|
|
|
|
av_opt_set_int(s->avrctx, "out_sample_rate", s->out_rate, 0);
|
2015-05-04 21:59:20 +00:00
|
|
|
av_opt_set_int(s->avrctx, "in_sample_fmt", in_samplefmt, 0);
|
|
|
|
av_opt_set_int(s->avrctx, "out_sample_fmt", out_samplefmtp, 0);
|
|
|
|
|
2015-10-26 14:53:47 +00:00
|
|
|
// Just needs the correct number of channels for deplanarization.
|
|
|
|
struct mp_chmap fake_chmap;
|
|
|
|
mp_chmap_set_unknown(&fake_chmap, map_out.num);
|
|
|
|
uint64_t fake_out_ch_layout = mp_chmap_to_lavc_unchecked(&fake_chmap);
|
2015-05-04 21:59:20 +00:00
|
|
|
if (!fake_out_ch_layout)
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2015-05-04 21:59:20 +00:00
|
|
|
av_opt_set_int(s->avrctx_out, "in_channel_layout", fake_out_ch_layout, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "out_channel_layout", fake_out_ch_layout, 0);
|
2015-10-26 14:53:47 +00:00
|
|
|
|
2015-05-04 21:59:20 +00:00
|
|
|
av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmtp, 0);
|
2013-11-09 22:20:58 +00:00
|
|
|
av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
|
2015-09-08 20:21:19 +00:00
|
|
|
av_opt_set_int(s->avrctx_out, "in_sample_rate", s->out_rate, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "out_sample_rate", s->out_rate, 0);
|
2013-11-09 22:20:58 +00:00
|
|
|
|
|
|
|
// API has weird requirements, quoting avresample.h:
|
|
|
|
// * This function can only be called when the allocated context is not open.
|
|
|
|
// * Also, the input channel layout must have already been set.
|
|
|
|
avresample_set_channel_mapping(s->avrctx, s->reorder_in);
|
|
|
|
|
2015-07-19 20:50:08 +00:00
|
|
|
if (avresample_open(s->avrctx) < 0 || avresample_open(s->avrctx_out) < 0) {
|
2014-08-17 01:29:09 +00:00
|
|
|
MP_ERR(af, "Cannot open Libavresample Context. \n");
|
2015-06-22 15:05:42 +00:00
|
|
|
goto error;
|
2013-11-09 22:20:58 +00:00
|
|
|
}
|
|
|
|
return AF_OK;
|
2015-06-22 15:05:42 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
close_lavrr(af);
|
|
|
|
return AF_ERROR;
|
2013-11-09 22:20:58 +00:00
|
|
|
}
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
static int control(struct af_instance *af, int cmd, void *arg)
|
|
|
|
{
|
2015-04-12 16:04:48 +00:00
|
|
|
struct af_resample *s = af->priv;
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case AF_CONTROL_REINIT: {
|
2015-04-12 16:04:48 +00:00
|
|
|
struct mp_audio *in = arg;
|
|
|
|
struct mp_audio *out = af->data;
|
2013-03-23 12:01:44 +00:00
|
|
|
struct mp_audio orig_in = *in;
|
|
|
|
|
|
|
|
if (((out->rate == in->rate) || (out->rate == 0)) &&
|
|
|
|
(out->format == in->format) &&
|
2013-04-05 18:39:52 +00:00
|
|
|
(mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) &&
|
2015-03-02 18:09:44 +00:00
|
|
|
s->allow_detach && s->playback_speed == 1.0)
|
2013-03-09 08:30:26 +00:00
|
|
|
return AF_DETACH;
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
if (out->rate == 0)
|
|
|
|
out->rate = in->rate;
|
|
|
|
|
2013-04-05 18:39:52 +00:00
|
|
|
if (mp_chmap_is_empty(&out->channels))
|
|
|
|
mp_audio_set_channels(out, &in->channels);
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
|
2013-11-09 22:20:58 +00:00
|
|
|
if (af_to_avformat(in->format) == AV_SAMPLE_FMT_NONE)
|
2013-11-15 20:25:05 +00:00
|
|
|
mp_audio_set_format(in, AF_FORMAT_FLOAT);
|
2015-06-16 20:38:37 +00:00
|
|
|
if (check_output_conversion(out->format) == AV_SAMPLE_FMT_NONE)
|
2013-04-05 17:47:51 +00:00
|
|
|
mp_audio_set_format(out, in->format);
|
2013-03-23 12:01:44 +00:00
|
|
|
|
2013-11-09 22:21:17 +00:00
|
|
|
int r = ((in->format == orig_in.format) &&
|
2013-04-05 18:39:52 +00:00
|
|
|
mp_chmap_equals(&in->channels, &orig_in.channels))
|
2013-11-09 22:21:17 +00:00
|
|
|
? AF_OK : AF_FALSE;
|
|
|
|
|
2015-07-19 20:54:03 +00:00
|
|
|
if (r == AF_OK)
|
2015-07-19 20:50:08 +00:00
|
|
|
r = configure_lavrr(af, in, out, true);
|
2013-11-09 22:21:17 +00:00
|
|
|
return r;
|
2013-03-23 12:01:44 +00:00
|
|
|
}
|
2013-11-18 13:16:08 +00:00
|
|
|
case AF_CONTROL_SET_FORMAT: {
|
2015-04-12 16:04:04 +00:00
|
|
|
int format = *(int *)arg;
|
2015-06-16 20:38:37 +00:00
|
|
|
if (format && check_output_conversion(format) == AV_SAMPLE_FMT_NONE)
|
2013-03-23 12:01:44 +00:00
|
|
|
return AF_FALSE;
|
|
|
|
|
2015-04-12 16:04:04 +00:00
|
|
|
mp_audio_set_format(af->data, format);
|
2013-03-23 12:01:44 +00:00
|
|
|
return AF_OK;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
2013-11-18 13:16:08 +00:00
|
|
|
case AF_CONTROL_SET_CHANNELS: {
|
2013-04-05 18:39:52 +00:00
|
|
|
mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
return AF_OK;
|
|
|
|
}
|
2013-11-18 13:16:08 +00:00
|
|
|
case AF_CONTROL_SET_RESAMPLE_RATE:
|
2015-04-12 16:04:48 +00:00
|
|
|
af->data->rate = *(int *)arg;
|
2013-03-09 08:30:26 +00:00
|
|
|
return AF_OK;
|
2015-03-02 18:09:44 +00:00
|
|
|
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
|
|
|
|
s->playback_speed = *(double *)arg;
|
|
|
|
return AF_OK;
|
|
|
|
}
|
2013-11-18 13:18:37 +00:00
|
|
|
case AF_CONTROL_RESET:
|
2015-06-22 15:05:42 +00:00
|
|
|
if (s->avrctx)
|
2015-06-22 12:59:51 +00:00
|
|
|
drop_all_output(s);
|
2013-11-18 13:18:37 +00:00
|
|
|
return AF_OK;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
|
|
|
return AF_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void uninit(struct af_instance *af)
|
|
|
|
{
|
2015-06-22 15:05:42 +00:00
|
|
|
close_lavrr(af);
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
|
|
|
|
2015-06-16 20:38:37 +00:00
|
|
|
// The LSB is always ignored.
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
|
|
#define SHIFT24(x) ((3-(x))*8)
|
|
|
|
#else
|
|
|
|
#define SHIFT24(x) (((x)+1)*8)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void extra_output_conversion(struct af_instance *af, struct mp_audio *mpa)
|
|
|
|
{
|
|
|
|
if (mpa->format == AF_FORMAT_S32 && af->data->format == AF_FORMAT_S24) {
|
|
|
|
size_t len = mp_audio_psize(mpa) / mpa->bps;
|
|
|
|
for (int s = 0; s < len; s++) {
|
|
|
|
uint32_t val = *((uint32_t *)mpa->planes[0] + s);
|
|
|
|
uint8_t *ptr = (uint8_t *)mpa->planes[0] + s * 3;
|
|
|
|
ptr[0] = val >> SHIFT24(0);
|
|
|
|
ptr[1] = val >> SHIFT24(1);
|
|
|
|
ptr[2] = val >> SHIFT24(2);
|
|
|
|
}
|
|
|
|
mp_audio_set_format(mpa, AF_FORMAT_S24);
|
|
|
|
}
|
2015-11-25 21:07:18 +00:00
|
|
|
|
|
|
|
for (int p = 0; p < mpa->num_planes; p++) {
|
|
|
|
void *ptr = mpa->planes[p];
|
|
|
|
int total = mpa->samples * mpa->spf;
|
|
|
|
if (af_fmt_from_planar(mpa->format) == AF_FORMAT_FLOAT) {
|
|
|
|
for (int s = 0; s < total; s++)
|
|
|
|
((float *)ptr)[s] = av_clipf(((float *)ptr)[s], -1.0f, 1.0f);
|
|
|
|
} else if (af_fmt_from_planar(mpa->format) == AF_FORMAT_DOUBLE) {
|
|
|
|
for (int s = 0; s < total; s++)
|
2015-11-25 23:25:28 +00:00
|
|
|
((double *)ptr)[s] = MPCLAMP(((double *)ptr)[s], -1.0, 1.0);
|
2015-11-25 21:07:18 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-16 20:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 15:53:23 +00:00
|
|
|
// This relies on the tricky way mpa was allocated.
|
2015-05-04 21:59:20 +00:00
|
|
|
static void reorder_planes(struct mp_audio *mpa, int *reorder,
|
|
|
|
struct mp_chmap *newmap)
|
2013-11-10 22:17:04 +00:00
|
|
|
{
|
|
|
|
struct mp_audio prev = *mpa;
|
2015-06-12 15:53:23 +00:00
|
|
|
mp_audio_set_channels(mpa, newmap);
|
|
|
|
|
|
|
|
// The trailing planes were never written by avrctx, they're the NA channels.
|
|
|
|
int next_na = prev.num_planes;
|
2015-05-04 21:59:20 +00:00
|
|
|
|
2015-06-12 15:53:23 +00:00
|
|
|
for (int n = 0; n < mpa->num_planes; n++) {
|
2015-05-04 21:59:20 +00:00
|
|
|
int src = reorder[n];
|
2015-06-12 15:53:23 +00:00
|
|
|
assert(src >= -1 && src < prev.num_planes);
|
|
|
|
if (src >= 0) {
|
|
|
|
mpa->planes[n] = prev.planes[src];
|
|
|
|
} else {
|
|
|
|
assert(next_na < mpa->num_planes);
|
|
|
|
mpa->planes[n] = prev.planes[next_na++];
|
|
|
|
af_fill_silence(mpa->planes[n], mpa->sstride * mpa->samples,
|
|
|
|
mpa->format);
|
2015-05-04 21:59:20 +00:00
|
|
|
}
|
2013-11-10 22:17:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-07 19:43:05 +00:00
|
|
|
static int filter_resample(struct af_instance *af, struct mp_audio *in)
|
2013-03-09 08:30:26 +00:00
|
|
|
{
|
2013-07-22 12:47:12 +00:00
|
|
|
struct af_resample *s = af->priv;
|
2013-03-09 08:30:26 +00:00
|
|
|
|
2015-06-02 20:20:04 +00:00
|
|
|
int samples = get_out_samples(s, in ? in->samples : 0);
|
2015-05-04 21:59:20 +00:00
|
|
|
|
2015-06-12 15:53:23 +00:00
|
|
|
struct mp_audio out_format = s->pool_fmt;
|
2015-05-04 21:59:20 +00:00
|
|
|
struct mp_audio *out = mp_audio_pool_get(af->out_pool, &out_format, samples);
|
2015-01-14 21:15:31 +00:00
|
|
|
if (!out)
|
|
|
|
goto error;
|
|
|
|
if (in)
|
|
|
|
mp_audio_copy_attributes(out, in);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
2015-06-22 15:05:42 +00:00
|
|
|
if (!s->avrctx)
|
|
|
|
goto error;
|
|
|
|
|
2013-11-10 22:17:04 +00:00
|
|
|
if (out->samples) {
|
2015-01-14 21:15:31 +00:00
|
|
|
out->samples = resample_frame(s->avrctx, out, in);
|
2013-11-10 22:17:04 +00:00
|
|
|
if (out->samples < 0)
|
2015-01-14 21:15:31 +00:00
|
|
|
goto error;
|
2013-11-10 20:40:51 +00:00
|
|
|
}
|
2013-03-09 08:30:26 +00:00
|
|
|
|
2015-06-12 15:53:23 +00:00
|
|
|
struct mp_audio real_out = *out;
|
|
|
|
mp_audio_copy_config(out, &s->avrctx_fmt);
|
|
|
|
|
2015-06-16 20:38:37 +00:00
|
|
|
if (out->samples && !mp_audio_config_equals(out, &s->pre_out_fmt)) {
|
2015-06-26 21:06:37 +00:00
|
|
|
assert(af_fmt_is_planar(out->format) && out->format == real_out.format);
|
2015-06-12 15:53:23 +00:00
|
|
|
reorder_planes(out, s->reorder_out, &s->pool_fmt.channels);
|
2015-06-16 20:38:37 +00:00
|
|
|
if (!mp_audio_config_equals(out, &s->pre_out_fmt)) {
|
|
|
|
struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer,
|
|
|
|
&s->pre_out_fmt,
|
2015-01-14 21:15:31 +00:00
|
|
|
out->samples);
|
|
|
|
if (!new)
|
|
|
|
goto error;
|
|
|
|
mp_audio_copy_attributes(new, out);
|
|
|
|
int out_samples = resample_frame(s->avrctx_out, new, out);
|
|
|
|
talloc_free(out);
|
|
|
|
out = new;
|
|
|
|
if (out_samples != new->samples)
|
|
|
|
goto error;
|
2013-11-10 22:17:04 +00:00
|
|
|
}
|
2013-04-05 22:56:01 +00:00
|
|
|
}
|
|
|
|
|
2015-06-16 20:38:37 +00:00
|
|
|
extra_output_conversion(af, out);
|
|
|
|
|
2015-01-14 21:15:31 +00:00
|
|
|
talloc_free(in);
|
|
|
|
if (out->samples) {
|
|
|
|
af_add_output_frame(af, out);
|
|
|
|
} else {
|
|
|
|
talloc_free(out);
|
|
|
|
}
|
2015-06-04 18:08:12 +00:00
|
|
|
|
|
|
|
af->delay = get_delay(s);
|
|
|
|
|
2013-12-04 23:01:46 +00:00
|
|
|
return 0;
|
2015-01-14 21:15:31 +00:00
|
|
|
error:
|
|
|
|
talloc_free(in);
|
|
|
|
talloc_free(out);
|
|
|
|
return -1;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
|
|
|
|
2015-10-07 19:43:05 +00:00
|
|
|
static int filter(struct af_instance *af, struct mp_audio *in)
|
|
|
|
{
|
|
|
|
struct af_resample *s = af->priv;
|
|
|
|
|
2015-10-12 19:12:05 +00:00
|
|
|
int new_rate = rate_from_speed(s->in_rate_af, s->playback_speed);
|
|
|
|
bool need_reinit = fabs(new_rate / (double)s->in_rate - 1) > 0.01;
|
|
|
|
|
2015-11-11 18:27:42 +00:00
|
|
|
if (s->avrctx) {
|
|
|
|
AVRational r = av_d2q(s->playback_speed * s->in_rate_af / s->in_rate,
|
|
|
|
INT_MAX / 2);
|
|
|
|
// Essentially, swr/avresample_set_compensation() does 2 things:
|
|
|
|
// - adjust output sample rate by sample_delta/compensation_distance
|
|
|
|
// - reset the adjustment after compensation_distance output samples
|
|
|
|
// Increase the compensation_distance to avoid undesired reset
|
|
|
|
// semantics - we want to keep the ratio for the whole frame we're
|
|
|
|
// feeding it, until the next filter() call.
|
|
|
|
int mult = INT_MAX / 2 / MPMAX(MPMAX(abs(r.num), abs(r.den)), 1);
|
|
|
|
r = (AVRational){ r.num * mult, r.den * mult };
|
|
|
|
if (avresample_set_compensation(s->avrctx, r.den - r.num, r.den) < 0)
|
2015-10-12 19:12:05 +00:00
|
|
|
need_reinit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_reinit && new_rate != s->in_rate) {
|
|
|
|
// Before reconfiguring, drain the audio that is still buffered
|
|
|
|
// in the resampler.
|
|
|
|
filter_resample(af, NULL);
|
|
|
|
// Reinitialize resampler.
|
|
|
|
configure_lavrr(af, &af->fmt_in, &af->fmt_out, false);
|
2015-10-07 19:43:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return filter_resample(af, in);
|
|
|
|
}
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
static int af_open(struct af_instance *af)
|
|
|
|
{
|
2013-07-22 12:47:12 +00:00
|
|
|
struct af_resample *s = af->priv;
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
af->control = control;
|
|
|
|
af->uninit = uninit;
|
2015-01-14 21:15:31 +00:00
|
|
|
af->filter_frame = filter;
|
2013-03-09 08:30:26 +00:00
|
|
|
|
2013-07-22 12:47:12 +00:00
|
|
|
if (s->opts.cutoff <= 0.0)
|
|
|
|
s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size);
|
2013-03-29 21:29:13 +00:00
|
|
|
|
2015-01-14 21:15:31 +00:00
|
|
|
s->reorder_buffer = mp_audio_pool_create(s);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
2015-06-22 15:05:42 +00:00
|
|
|
return AF_OK;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
|
|
|
|
2013-07-22 12:47:12 +00:00
|
|
|
#define OPT_BASE_STRUCT struct af_resample
|
|
|
|
|
2014-06-10 21:56:05 +00:00
|
|
|
const struct af_info af_info_lavrresample = {
|
2013-10-23 17:05:47 +00:00
|
|
|
.info = "Sample frequency conversion using libavresample",
|
|
|
|
.name = "lavrresample",
|
|
|
|
.open = af_open,
|
2013-07-22 12:47:12 +00:00
|
|
|
.priv_size = sizeof(struct af_resample),
|
|
|
|
.priv_defaults = &(const struct af_resample) {
|
|
|
|
.opts = {
|
|
|
|
.filter_size = 16,
|
|
|
|
.cutoff = 0.0,
|
|
|
|
.phase_shift = 10,
|
2015-09-08 20:04:45 +00:00
|
|
|
.normalize = 1,
|
2013-07-22 12:47:12 +00:00
|
|
|
},
|
2015-03-02 18:09:44 +00:00
|
|
|
.playback_speed = 1.0,
|
2013-07-22 12:47:12 +00:00
|
|
|
.allow_detach = 1,
|
|
|
|
},
|
|
|
|
.options = (const struct m_option[]) {
|
|
|
|
OPT_INTRANGE("filter-size", opts.filter_size, 0, 0, 32),
|
|
|
|
OPT_INTRANGE("phase-shift", opts.phase_shift, 0, 0, 30),
|
|
|
|
OPT_FLAG("linear", opts.linear, 0),
|
|
|
|
OPT_DOUBLE("cutoff", opts.cutoff, M_OPT_RANGE, .min = 0, .max = 1),
|
|
|
|
OPT_FLAG("detach", allow_detach, 0),
|
2015-09-08 20:04:45 +00:00
|
|
|
OPT_FLAG("normalize", opts.normalize, 0),
|
2014-08-02 01:12:09 +00:00
|
|
|
OPT_KEYVALUELIST("o", avopts, 0),
|
2013-07-22 12:47:12 +00:00
|
|
|
{0}
|
|
|
|
},
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|