What you need to do is build a filter graph and process the audio stream through this graph. In your case, the graph is just INPUT ("abuffer") -> VOLUME -> OUTPUT ("abuffersink"). Here is an example console application that demonstrates this. It is freely based on ffmpeg filtering_audio , filter_audio and remuxing samples .
You can use it as follows:
ChangeVolume.exe http:
And here is the code:
class Program { static unsafe void Main(string[] args) { Console.WriteLine(@"Current directory: " + Environment.CurrentDirectory); Console.WriteLine(@"Running in {0}-bit mode.", Environment.Is64BitProcess ? @"64" : @"32"); // adapt this to your context var ffmpegPath = string.Format(@"../../../FFmpeg/bin/{0}", Environment.Is64BitProcess ? @"x64" : @"x86"); InteropHelper.SetDllDirectory(ffmpegPath); int ret, i; if (args.Length < 3) { Console.WriteLine("usage: ChangeVolume input output <volume ratio>"); return; } string in_filename = args[0]; string out_filename = args[1]; double ratio = double.Parse(args[2]); ffmpeg.av_register_all(); ffmpeg.avfilter_register_all(); // open input file AVFormatContext* ifmt_ctx = null; InteropHelper.Check(ffmpeg.avformat_open_input(&ifmt_ctx, in_filename, null, null)); // dump input ffmpeg.av_dump_format(ifmt_ctx, 0, in_filename, 0); // get streams info to determine audio stream index InteropHelper.Check(ffmpeg.avformat_find_stream_info(ifmt_ctx, null)); // determine input decoder AVCodec* dec; int audio_stream_index = ffmpeg.av_find_best_stream(ifmt_ctx, AVMediaType.AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0); AVCodecContext* dec_ctx = ifmt_ctx->streams[audio_stream_index]->codec; // open input decoder InteropHelper.Check(ffmpeg.avcodec_open2(dec_ctx, dec, null)); // build a filter graph AVFilterContext* buffersrc_ctx; AVFilterContext* buffersink_ctx; AVFilterGraph* filter_graph = init_filter_graph(ifmt_ctx, dec_ctx, audio_stream_index, &buffersrc_ctx, &buffersink_ctx, ratio); // prepare output AVFormatContext* ofmt_ctx = null; InteropHelper.Check(ffmpeg.avformat_alloc_output_context2(&ofmt_ctx, null, null, out_filename)); InteropHelper.Check(ofmt_ctx); // create output streams AVCodecContext* enc_ctx = null; ofmt_ctx->oformat->flags |= InteropHelper.AVFMT_NOTIMESTAMPS; for (i = 0; i < ifmt_ctx->nb_streams; i++) { AVStream* in_stream = ifmt_ctx->streams[i]; if (in_stream->codec->codec_type == AVMediaType.AVMEDIA_TYPE_DATA) // skip these continue; AVStream* out_stream = ffmpeg.avformat_new_stream(ofmt_ctx, in_stream->codec->codec); InteropHelper.Check(out_stream); InteropHelper.Check(ffmpeg.avcodec_copy_context(out_stream->codec, in_stream->codec)); out_stream->codec->codec_tag = 0; if ((ofmt_ctx->oformat->flags & InteropHelper.AVFMT_GLOBALHEADER) != 0) { out_stream->codec->flags |= InteropHelper.AV_CODEC_FLAG_GLOBAL_HEADER; } if (i == audio_stream_index) { // create audio encoder from audio decoder AVCodec* enc = ffmpeg.avcodec_find_encoder(dec_ctx->codec_id); InteropHelper.Check(enc); enc_ctx = ffmpeg.avcodec_alloc_context3(enc); InteropHelper.Check(enc_ctx); enc_ctx->sample_rate = dec_ctx->sample_rate; enc_ctx->channel_layout = dec_ctx->channel_layout; enc_ctx->channels = ffmpeg.av_get_channel_layout_nb_channels(enc_ctx->channel_layout); enc_ctx->sample_fmt = enc->sample_fmts[0]; enc_ctx->time_base.num = 1; enc_ctx->time_base.den = enc_ctx->sample_rate; InteropHelper.Check(ffmpeg.avcodec_open2(enc_ctx, enc, null)); } } // dump output ffmpeg.av_dump_format(ofmt_ctx, 0, out_filename, 1); if ((ofmt_ctx->oformat->flags & InteropHelper.AVFMT_NOFILE) == 0) { // open output file InteropHelper.Check(ffmpeg.avio_open(&ofmt_ctx->pb, out_filename, InteropHelper.AVIO_FLAG_WRITE)); } // write output file header InteropHelper.Check(ffmpeg.avformat_write_header(ofmt_ctx, null)); // read all packets and process AVFrame* frame = ffmpeg.av_frame_alloc(); AVFrame* filt_frame = ffmpeg.av_frame_alloc(); while (true) { AVStream* in_stream; AVStream* out_stream; AVPacket pkt; ret = ffmpeg.av_read_frame(ifmt_ctx, &pkt); if (ret < 0) break; in_stream = ifmt_ctx->streams[pkt.stream_index]; if (in_stream->codec->codec_type == AVMediaType.AVMEDIA_TYPE_DATA) continue; // audio stream? we need to pass it through our filter graph if (pkt.stream_index == audio_stream_index) { // decode audio (packet -> frame) int got_frame = 0; InteropHelper.Check(ffmpeg.avcodec_decode_audio4(dec_ctx, frame, &got_frame, &pkt)); if (got_frame > 0) { // add the frame into the filter graph InteropHelper.Check(ffmpeg.av_buffersrc_add_frame(buffersrc_ctx, frame)); while (true) { // get the frame out from the filter graph ret = ffmpeg.av_buffersink_get_frame(buffersink_ctx, filt_frame); const int EAGAIN = 11; if (ret == -EAGAIN) break; InteropHelper.Check(ret); // encode audio (frame -> packet) AVPacket enc_pkt = new AVPacket(); int got_packet = 0; InteropHelper.Check(ffmpeg.avcodec_encode_audio2(enc_ctx, &enc_pkt, filt_frame, &got_packet)); enc_pkt.stream_index = pkt.stream_index; InteropHelper.Check(ffmpeg.av_interleaved_write_frame(ofmt_ctx, &enc_pkt)); ffmpeg.av_frame_unref(filt_frame); } } } else { // write other (video) streams out_stream = ofmt_ctx->streams[pkt.stream_index]; pkt.pts = ffmpeg.av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX); pkt.dts = ffmpeg.av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX); pkt.duration = ffmpeg.av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); pkt.pos = -1; InteropHelper.Check(ffmpeg.av_interleaved_write_frame(ofmt_ctx, &pkt)); } ffmpeg.av_packet_unref(&pkt); } // write trailer, close file ffmpeg.av_write_trailer(ofmt_ctx); ffmpeg.avformat_close_input(&ifmt_ctx); if ((ofmt_ctx->oformat->flags & InteropHelper.AVFMT_NOFILE) == 0) { ffmpeg.avio_closep(&ofmt_ctx->pb); } ffmpeg.avformat_free_context(ofmt_ctx); ffmpeg.av_frame_free(&filt_frame); ffmpeg.av_frame_free(&frame); ffmpeg.avfilter_graph_free(&filter_graph); return; } static unsafe AVFilterGraph* init_filter_graph(AVFormatContext* format, AVCodecContext* codec, int audio_stream_index, AVFilterContext** buffersrc_ctx, AVFilterContext** buffersink_ctx, double volumeRatio) { // create graph var filter_graph = ffmpeg.avfilter_graph_alloc(); InteropHelper.Check(filter_graph); // add input filter var abuffersrc = ffmpeg.avfilter_get_by_name("abuffer"); if (abuffersrc == null) InteropHelper.CheckTag("\x00F8FIL"); string args = string.Format("sample_fmt={0}:channel_layout={1}:sample_rate={2}:time_base={3}/{4}", (int)codec->sample_fmt, codec->channel_layout, codec->sample_rate, format->streams[audio_stream_index]->time_base.num, format->streams[audio_stream_index]->time_base.den); InteropHelper.Check(ffmpeg.avfilter_graph_create_filter(buffersrc_ctx, abuffersrc, "IN", args, null, filter_graph)); // add volume filter var volume = ffmpeg.avfilter_get_by_name("volume"); if (volume == null) InteropHelper.CheckTag("\x00F8FIL"); AVFilterContext* volume_ctx; InteropHelper.Check(ffmpeg.avfilter_graph_create_filter(&volume_ctx, volume, "VOL", "volume=" + volumeRatio.ToString(CultureInfo.InvariantCulture), null, filter_graph)); // add output filter var abuffersink = ffmpeg.avfilter_get_by_name("abuffersink"); if (abuffersink == null) InteropHelper.CheckTag("\x00F8FIL"); InteropHelper.Check(ffmpeg.avfilter_graph_create_filter(buffersink_ctx, abuffersink, "OUT", "", null, filter_graph)); // connect input -> volume -> output InteropHelper.Check(ffmpeg.avfilter_link(*buffersrc_ctx, 0, volume_ctx, 0)); InteropHelper.Check(ffmpeg.avfilter_link(volume_ctx, 0, *buffersink_ctx, 0)); InteropHelper.Check(ffmpeg.avfilter_graph_config(filter_graph, null)); return filter_graph; } }
It uses the InteropHelper utility class derived from AutoGen's:
public class InteropHelper { [DllImport("kernel32", SetLastError = true)] public static extern bool SetDllDirectory(string lpPathName); public static readonly int AVERROR_EOF = -GetTag("EOF "); public static readonly int AVERROR_UNKNOWN = -GetTag("UNKN"); public static readonly int AVFMT_GLOBALHEADER = 0x0040; public static readonly int AVFMT_NOFILE = 0x0001; public static readonly int AVIO_FLAG_WRITE = 2; public static readonly int AV_CODEC_FLAG_GLOBAL_HEADER = (1 << 22); public static readonly int AV_ROUND_ZERO = 0; public static readonly int AV_ROUND_INF = 1; public static readonly int AV_ROUND_DOWN = 2; public static readonly int AV_ROUND_UP = 3; public static readonly int AV_ROUND_PASS_MINMAX = 8192; public static readonly int AV_ROUND_NEAR_INF = 5; public static readonly int AVFMT_NOTIMESTAMPS = 0x0080; public static unsafe void Check(void* ptr) { if (ptr != null) return; const int ENOMEM = 12; Check(-ENOMEM); } public static unsafe void Check(IntPtr ptr) { if (ptr != IntPtr.Zero) return; Check((void*)null); }