/* * This file is part of mpv. * * mpv is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with mpv. If not, see . */ #include "audio/aframe.h" #include "audio/format.h" #include "filters/f_autoconvert.h" #include "filters/filter_internal.h" #include "filters/user_filters.h" #include "options/m_option.h" struct f_opts { int in_format; int in_srate; struct m_channels in_channels; int out_format; int out_srate; struct m_channels out_channels; int fail; }; struct priv { struct f_opts *opts; struct mp_pin *in_pin; }; static void process(struct mp_filter *f) { struct priv *p = f->priv; if (!mp_pin_can_transfer_data(f->ppins[1], p->in_pin)) return; struct mp_frame frame = mp_pin_out_read(p->in_pin); if (p->opts->fail) { MP_ERR(f, "Failing on purpose.\n"); goto error; } if (frame.type == MP_FRAME_EOF) { mp_pin_in_write(f->ppins[1], frame); return; } if (frame.type != MP_FRAME_AUDIO) { MP_ERR(f, "audio frame expected\n"); goto error; } struct mp_aframe *in = frame.data; if (p->opts->out_channels.num_chmaps > 0) { if (!mp_aframe_set_chmap(in, &p->opts->out_channels.chmaps[0])) { MP_ERR(f, "could not force output channels\n"); goto error; } } if (p->opts->out_srate) mp_aframe_set_rate(in, p->opts->out_srate); mp_pin_in_write(f->ppins[1], frame); return; error: mp_frame_unref(&frame); mp_filter_internal_mark_failed(f); } static const struct mp_filter_info af_format_filter = { .name = "format", .priv_size = sizeof(struct priv), .process = process, }; static struct mp_filter *af_format_create(struct mp_filter *parent, void *options) { struct mp_filter *f = mp_filter_create(parent, &af_format_filter); if (!f) { talloc_free(options); return NULL; } struct priv *p = f->priv; p->opts = talloc_steal(p, options); mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out"); struct mp_autoconvert *conv = mp_autoconvert_create(f); if (!conv) abort(); if (p->opts->in_format) mp_autoconvert_add_afmt(conv, p->opts->in_format); if (p->opts->in_srate) mp_autoconvert_add_srate(conv, p->opts->in_srate); if (p->opts->in_channels.num_chmaps > 0) mp_autoconvert_add_chmap(conv, &p->opts->in_channels.chmaps[0]); mp_pin_connect(conv->f->pins[0], f->ppins[0]); p->in_pin = conv->f->pins[1]; return f; } #define OPT_BASE_STRUCT struct f_opts const struct mp_user_filter_entry af_format = { .desc = { .name = "format", .description = "Force audio format", .priv_size = sizeof(struct f_opts), .options = (const struct m_option[]) { OPT_AUDIOFORMAT("format", in_format, 0), OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000), OPT_CHANNELS("channels", in_channels, 0, .min = 1), OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000), OPT_CHANNELS("out-channels", out_channels, 0, .min = 1), OPT_FLAG("fail", fail, 0), {0} }, }, .create = af_format_create, };