可以通过使用音频库或框架来实现。以下是一个可能的解决方案:
#include <iostream>
#include <fstream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
// 回调函数,用于向音频设备提供音频数据
void audio_callback(void* userdata, Uint8* stream, int len) {
AVPacket packet;
AVCodecContext* codec_ctx = (AVCodecContext*)userdata;
int audio_size = 0;
static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
static unsigned int audio_buf_size = 0;
static unsigned int audio_buf_index = 0;
while (len > 0) {
if (audio_buf_index >= audio_buf_size) {
// 读取下一个音频帧
if (av_read_frame(format_ctx, &packet) < 0) {
break;
}
// 解码音频帧
int ret = avcodec_send_packet(codec_ctx, &packet);
if (ret < 0) {
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
break;
}
// 将解码后的音频数据拷贝到缓冲区
int data_size = av_samples_get_buffer_size(NULL, codec_ctx->channels, frame->nb_samples, codec_ctx->sample_fmt, 1);
memcpy(audio_buf, frame->data[0], data_size);
audio_buf_size = data_size;
audio_buf_index = 0;
}
av_packet_unref(&packet);
}
// 将音频数据拷贝到音频设备的缓冲区
int remaining = audio_buf_size - audio_buf_index;
int to_copy = len > remaining ? remaining : len;
memcpy(stream, audio_buf + audio_buf_index, to_copy);
len -= to_copy;
stream += to_copy;
audio_buf_index += to_copy;
}
}
int main() {
// 初始化FFmpeg和SDL
av_register_all();
avformat_network_init();
SDL_Init(SDL_INIT_AUDIO);
// 打开mp3文件
AVFormatContext* format_ctx = avformat_alloc_context();
if (avformat_open_input(&format_ctx, "input.mp3", NULL, NULL) != 0) {
std::cerr << "Failed to open input file" << std::endl;
return -1;
}
// 查找音频流信息
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
std::cerr << "Failed to find stream information" << std::endl;
return -1;
}
// 查找音频解码器
AVCodec* codec = NULL;
int audio_stream_index = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (audio_stream_index < 0) {
std::cerr << "Failed to find audio stream" << std::endl;
return -1;
}
// 创建音频解码器上下文
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codec_ctx, format_ctx->streams[audio_stream_index]->codecpar) < 0) {
std::cerr << "Failed to copy codec parameters to codec context" << std::endl;
return -1;
}
// 打开音频解码器
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
std::cerr << "Failed to open audio codec" << std::endl;
return -1;
}
// 创建音频设备参数
SDL_AudioSpec wanted_spec, obtained_spec;
wanted_spec.freq = codec_ctx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = codec_ctx->channels;
wanted_spec.silence = 0;
wanted_spec.samples = 1024;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = codec_ctx;
// 打开音频设备
if (SDL_OpenAudio(&wanted_spec, &obtained_spec) < 0) {
std::cerr << "Failed to open audio device" << std::endl;
return -1;
}
// 开始播放音频
SDL_PauseAudio(0);
// 等待音频播放完成
while (audio_buf_index < audio_buf_size) {
SDL_Delay(100);
}
// 关闭音频设备
SDL_CloseAudio();
// 释放资源
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
avformat_free_context(format_ctx);
SDL_Quit();
return 0;
}
请注意,上述示例代码仅供参考,具体实现可能因使用的库和框架而有所不同。在实际应用中,您可能需要根据自己的需求进行适当的修改和调整。
领取专属 10元无门槛券
手把手带您无忧上云