C实现用ffmpeg MP3转8K PCM
时间: 2024-04-25 07:26:07 浏览: 150
ffmpeg MP3 转换 pcm
4星 · 用户满意度95%
可以使用ffmpeg库来实现MP3转8K PCM的功能。以下是一个简单的C语言代码示例:
```c
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
int main(int argc, char *argv[]) {
AVFormatContext *format_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
int stream_index = -1;
int ret = 0;
int got_frame = 0;
int i, j;
// 初始化FFmpeg库
av_register_all();
avformat_network_init();
// 打开输入文件
if ((ret = avformat_open_input(&format_ctx, argv[1], NULL, NULL)) < 0) {
fprintf(stderr, "Could not open input file '%s'\n", argv[1]);
goto end;
}
// 查找音频流
if ((ret = avformat_find_stream_info(format_ctx, NULL)) < 0) {
fprintf(stderr, "Could not find stream information\n");
goto end;
}
for (i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index == -1) {
fprintf(stderr, "Could not find audio stream\n");
goto end;
}
// 获取解码器
codec = avcodec_find_decoder(format_ctx->streams[stream_index]->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "Could not find decoder\n");
goto end;
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Could not allocate codec context\n");
goto end;
}
if ((ret = avcodec_parameters_to_context(codec_ctx, format_ctx->streams[stream_index]->codecpar)) < 0) {
fprintf(stderr, "Could not initialize codec context\n");
goto end;
}
if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0) {
fprintf(stderr, "Could not open codec\n");
goto end;
}
// 初始化重采样上下文
SwrContext *swr_ctx = swr_alloc_set_opts(NULL,
AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16, 8000,
av_get_default_channel_layout(codec_ctx->channels), codec_ctx->sample_fmt, codec_ctx->sample_rate,
0, NULL);
if (!swr_ctx) {
fprintf(stderr, "Could not allocate resampling context\n");
goto end;
}
if ((ret = swr_init(swr_ctx)) < 0) {
fprintf(stderr, "Could not initialize resampling context\n");
goto end;
}
// 读取并解码音频帧
while ((ret = av_read_frame(format_ctx, packet)) == 0) {
if (packet->stream_index == stream_index) {
ret = avcodec_send_packet(codec_ctx, packet);
if (ret < 0) {
fprintf(stderr, "Error sending packet to decoder\n");
goto end;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error receiving frame from decoder\n");
goto end;
}
// 重采样
uint8_t *out_buf;
int out_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples, 8000, frame->sample_rate, AV_ROUND_UP);
av_samples_alloc(&out_buf, NULL, 1, out_samples, AV_SAMPLE_FMT_S16, 0);
out_samples = swr_convert(swr_ctx, &out_buf, out_samples, (const uint8_t **)frame->data, frame->nb_samples);
// 输出PCM数据
fwrite(out_buf, sizeof(uint8_t), out_samples * 2, stdout);
av_free(out_buf);
}
}
av_packet_unref(packet);
}
end:
if (codec_ctx) {
avcodec_close(codec_ctx);
avcodec_free_context(&codec_ctx);
}
if (format_ctx) {
avformat_close_input(&format_ctx);
avformat_free_context(format_ctx);
}
if (packet) {
av_packet_free(&packet);
}
if (frame) {
av_frame_free(&frame);
}
if (swr_ctx) {
swr_free(&swr_ctx);
}
return ret < 0;
}
```
你可以将上述代码保存为 `mp3_to_pcm.c`,然后使用以下命令编译:
```
gcc -o mp3_to_pcm mp3_to_pcm.c -lavformat -lavcodec -lswresample
```
然后执行以下命令进行转换:
```
./mp3_to_pcm input.mp3 > output.pcm
```
其中,`input.mp3` 是输入MP3文件名,`output.pcm` 是输出PCM文件名。注意,输出的PCM数据是单声道、16位、8000Hz的。
阅读全文