ffmpeg 对视频音量进行调整 c++
时间: 2023-07-31 21:11:05 浏览: 383
可以使用 ffmpeg 的音频过滤器 `volume` 来进行音量调整。以下是一个简单的 C++ 代码示例:
```c++
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfiltergraph.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/avfilter.h>
using namespace std;
int main(int argc, char** argv)
{
if (argc < 4) {
cout << "Usage: " << argv[0] << " <input_file> <output_file> <volume>" << endl;
return 1;
}
const char* input_file = argv[1];
const char* output_file = argv[2];
const char* volume = argv[3];
av_register_all();
avfilter_register_all();
AVFormatContext* fmt_ctx = NULL;
if (avformat_open_input(&fmt_ctx, input_file, NULL, NULL) != 0) {
cout << "Cannot open input file: " << input_file << endl;
return 1;
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
cout << "Cannot find stream information" << endl;
return 1;
}
AVCodec* codec = NULL;
int stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (stream_idx < 0) {
cout << "Cannot find audio stream" << endl;
return 1;
}
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (codec_ctx == NULL) {
cout << "Cannot allocate codec context" << endl;
return 1;
}
avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[stream_idx]->codecpar);
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
cout << "Cannot open codec" << endl;
return 1;
}
AVFilterGraph* filter_graph = avfilter_graph_alloc();
if (filter_graph == NULL) {
cout << "Cannot allocate filter graph" << endl;
return 1;
}
AVFilterContext* src_ctx = NULL;
AVFilterContext* sink_ctx = NULL;
char args[512];
snprintf(args, sizeof(args), "volume=%s", volume);
const AVFilter* src = avfilter_get_by_name("abuffer");
const AVFilter* sink = avfilter_get_by_name("abuffersink");
const AVFilter* volume_filter = avfilter_get_by_name("volume");
if (avfilter_graph_create_filter(&src_ctx, src, "src", NULL, NULL, filter_graph) < 0) {
cout << "Cannot create buffer source" << endl;
return 1;
}
if (avfilter_graph_create_filter(&sink_ctx, sink, "sink", NULL, NULL, filter_graph) < 0) {
cout << "Cannot create buffer sink" << endl;
return 1;
}
if (avfilter_graph_create_filter(&volume_ctx, volume_filter, "volume", args, NULL, filter_graph) < 0) {
cout << "Cannot create volume filter" << endl;
return 1;
}
AVFilterInOut* outputs = avfilter_inout_alloc();
AVFilterInOut* inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = src_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = sink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
if (avfilter_graph_parse_ptr(filter_graph, "anull", &inputs, &outputs, NULL) < 0) {
cout << "Cannot parse filter graph" << endl;
return 1;
}
if (avfilter_graph_config(filter_graph, NULL) < 0) {
cout << "Cannot configure filter graph" << endl;
return 1;
}
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
AVFrame* frame = av_frame_alloc();
FILE* fout = fopen(output_file, "wb");
if (fout == NULL) {
cout << "Cannot open output file: " << output_file << endl;
return 1;
}
AVRational time_base = fmt_ctx->streams[stream_idx]->time_base;
int ret;
while (av_read_frame(fmt_ctx, &pkt) == 0) {
if (pkt.stream_index != stream_idx) {
av_packet_unref(&pkt);
continue;
}
ret = avcodec_send_packet(codec_ctx, &pkt);
if (ret < 0) {
cout << "Error sending packet to decoder" << endl;
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
cout << "Error receiving frame from decoder" << endl;
goto end;
}
ret = av_buffersrc_add_frame_flags(src_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
if (ret < 0) {
cout << "Error submitting frame to source buffer" << endl;
goto end;
}
while (1) {
AVFrame* filtered_frame = av_frame_alloc();
ret = av_buffersink_get_frame_flags(sink_ctx, filtered_frame, 0);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_free(&filtered_frame);
break;
} else if (ret < 0) {
av_frame_free(&filtered_frame);
cout << "Error getting filtered frame from sink buffer" << endl;
goto end;
}
filtered_frame->pts = av_rescale_q(filtered_frame->pts, codec_ctx->time_base, time_base);
filtered_frame->pkt_dts = av_rescale_q(filtered_frame->pkt_dts, codec_ctx->time_base, time_base);
ret = avcodec_send_frame(codec_ctx, filtered_frame);
if (ret < 0) {
cout << "Error sending frame to encoder" << endl;
av_frame_free(&filtered_frame);
goto end;
}
while (ret >= 0) {
AVPacket enc_pkt;
av_init_packet(&enc_pkt);
enc_pkt.data = NULL;
enc_pkt.size = 0;
ret = avcodec_receive_packet(codec_ctx, &enc_pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_packet_unref(&enc_pkt);
break;
} else if (ret < 0) {
cout << "Error receiving packet from encoder" << endl;
av_packet_unref(&enc_pkt);
goto end;
}
enc_pkt.pts = av_rescale_q(enc_pkt.pts, codec_ctx->time_base, time_base);
enc_pkt.dts = av_rescale_q(enc_pkt.dts, codec_ctx->time_base, time_base);
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0) {
cout << "Error writing packet" << endl;
av_packet_unref(&enc_pkt);
goto end;
}
av_packet_unref(&enc_pkt);
}
av_frame_free(&filtered_frame);
}
av_frame_unref(frame);
}
av_packet_unref(&pkt);
}
av_write_trailer(fmt_ctx);
end:
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
avfilter_graph_free(&filter_graph);
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
fclose(fout);
return 0;
}
```
这个代码会读取一个音频文件,然后使用 `volume` 过滤器增加或减少音量,并将结果写入另一个文件。你需要把 `volume` 参数设置为一个浮点数,表示音量的缩放因子,例如 `0.5` 表示将音量减半,`2.0` 表示将音量增加一倍。
阅读全文