1/* 2 * Copyright (c) 2013 Nicolas George 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public License 8 * as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavutil/opt.h" 22#include "avfilter.h" 23#include "internal.h" 24 25typedef struct { 26 const AVClass *class; 27 int sample_rate; 28 int rescale_pts; 29} ASetRateContext; 30 31#define CONTEXT ASetRateContext 32#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM 33 34#define OPT_GENERIC(name, field, def, min, max, descr, type, deffield, ...) \ 35 { name, descr, offsetof(CONTEXT, field), AV_OPT_TYPE_ ## type, \ 36 { .deffield = def }, min, max, FLAGS, __VA_ARGS__ } 37 38#define OPT_INT(name, field, def, min, max, descr, ...) \ 39 OPT_GENERIC(name, field, def, min, max, descr, INT, i64, __VA_ARGS__) 40 41static const AVOption asetrate_options[] = { 42 OPT_INT("sample_rate", sample_rate, 44100, 1, INT_MAX, "set the sample rate"), 43 OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate"), 44 {NULL}, 45}; 46 47AVFILTER_DEFINE_CLASS(asetrate); 48 49static av_cold int query_formats(AVFilterContext *ctx) 50{ 51 ASetRateContext *sr = ctx->priv; 52 int sample_rates[] = { sr->sample_rate, -1 }; 53 54 ff_formats_ref(ff_make_format_list(sample_rates), 55 &ctx->outputs[0]->in_samplerates); 56 return 0; 57} 58 59static av_cold int config_props(AVFilterLink *outlink) 60{ 61 AVFilterContext *ctx = outlink->src; 62 ASetRateContext *sr = ctx->priv; 63 AVFilterLink *inlink = ctx->inputs[0]; 64 AVRational intb = ctx->inputs[0]->time_base; 65 int inrate = inlink->sample_rate; 66 67 if (intb.num == 1 && intb.den == inrate) { 68 outlink->time_base.num = 1; 69 outlink->time_base.den = outlink->sample_rate; 70 } else { 71 outlink->time_base = intb; 72 sr->rescale_pts = 1; 73 if (av_q2d(intb) > 1.0 / FFMAX(inrate, outlink->sample_rate)) 74 av_log(ctx, AV_LOG_WARNING, "Time base is inaccurate\n"); 75 } 76 return 0; 77} 78 79static int filter_frame(AVFilterLink *inlink, AVFrame *frame) 80{ 81 AVFilterContext *ctx = inlink->dst; 82 ASetRateContext *sr = ctx->priv; 83 AVFilterLink *outlink = ctx->outputs[0]; 84 85 frame->sample_rate = outlink->sample_rate; 86 if (sr->rescale_pts) 87 frame->pts = av_rescale(frame->pts, inlink->sample_rate, 88 outlink->sample_rate); 89 return ff_filter_frame(outlink, frame); 90} 91 92static const AVFilterPad asetrate_inputs[] = { 93 { 94 .name = "default", 95 .type = AVMEDIA_TYPE_AUDIO, 96 .filter_frame = filter_frame, 97 }, 98 { NULL } 99}; 100 101static const AVFilterPad asetrate_outputs[] = { 102 { 103 .name = "default", 104 .type = AVMEDIA_TYPE_AUDIO, 105 .config_props = config_props, 106 }, 107 { NULL } 108}; 109 110AVFilter ff_af_asetrate = { 111 .name = "asetrate", 112 .description = NULL_IF_CONFIG_SMALL("Change the sample rate without " 113 "altering the data."), 114 .query_formats = query_formats, 115 .priv_size = sizeof(ASetRateContext), 116 .inputs = asetrate_inputs, 117 .outputs = asetrate_outputs, 118 .priv_class = &asetrate_class, 119}; 120