鱼C论坛

 找回密码
 立即注册
查看: 2231|回复: 6

[已解决]Mac系统C++如何播放MP3?

[复制链接]
发表于 2021-9-4 17:45:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Mac系统下C++无法使用Windows.h头文件的Beep,该如何播放MP3呢?
最好是C++自带的头文件,如果不是,请写下头文件的下载地址哦
最佳答案
2021-9-6 15:48:12
下面这个代码花了我大概三天的时间,因为学到了很多东西,所以值得,^_^

音频视频处理领域,ffmpeg 大概是最权威的了
ffmpeg 跨平台,mac 肯定能用
我的程序中还使用了 /dev/dsp 设备,不知道 mac 能不能用
这个程序把解码出来的音频数据发往 dsp 设备,如果 dsp 设备不能用,那就使用 sdl,把发往 dsp 的数据发送到 sdl 进行播放
还有,因为使用了 ffmpeg,这个程序可不仅仅支持 mp3,ffmpeg 支持绝大多数的音频视频格式
还有,我刚刚才看到是要求 C++ 写,C语言代码在下面,如果你真的必须是要 C++ 的话,自己改代码吧,^_^
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <sys/ioctl.h>
  6. #include <linux/soundcard.h>
  7. #include <libavformat/avformat.h>
  8. #include <libavcodec/codec.h>
  9. #include <libswresample/swresample.h>

  10. int main(int argc, char *argv[]) {
  11.     if(argc != 2) return -1;
  12.     const char *filename = argv[1];
  13.     AVFormatContext *format_ctx = avformat_alloc_context();
  14.     avformat_open_input(&format_ctx, filename, NULL, NULL);
  15.     avformat_find_stream_info(format_ctx, NULL);
  16.     int stream_idx = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
  17.     AVCodecParameters *codecpar = format_ctx->streams[stream_idx]->codecpar;
  18.     AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
  19.     AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
  20.     avcodec_parameters_to_context(codec_ctx, codecpar);
  21.     avcodec_open2(codec_ctx, codec, NULL);

  22.     int dsp = open("/dev/dsp", O_WRONLY);
  23.     int channels = codecpar->channels;
  24.     int sample_rate = codecpar->sample_rate;
  25.     int sample_fmt = AFMT_S16_LE;   // dsp 有好多格式都不支持,这里使用固定格式,下面把数据转换到这个格式
  26.     ioctl(dsp, SNDCTL_DSP_CHANNELS, &channels);
  27.     ioctl(dsp, SNDCTL_DSP_SPEED, &sample_rate);
  28.     ioctl(dsp, SNDCTL_DSP_SETFMT, &sample_fmt);
  29.     printf("channels: %d, sample_rate: %d, sample_fmt: %d\n", channels, sample_rate,
  30.             av_get_bytes_per_sample(codecpar->format) * 8);
  31.     SwrContext *swr_ctx = swr_alloc();
  32.     int channel_layout = av_get_default_channel_layout(codecpar->channels);     // codecpar->channel_layout 有可能为 0
  33.     swr_alloc_set_opts(swr_ctx, channel_layout, AV_SAMPLE_FMT_S16, codecpar->sample_rate,
  34.             channel_layout, codecpar->format, codecpar->sample_rate, 0, NULL);
  35.     swr_init(swr_ctx);
  36.     AVPacket *pkt = av_packet_alloc();
  37.     AVFrame *frame = av_frame_alloc();
  38.     size_t buffer_size = 48000 * 4;
  39.     uint8_t *buffer = av_malloc(buffer_size);
  40.     while(av_read_frame(format_ctx, pkt) == 0) {
  41.         if(pkt->stream_index == stream_idx) {
  42.             avcodec_send_packet(codec_ctx, pkt);
  43.             avcodec_receive_frame(codec_ctx, frame);
  44.             swr_convert(swr_ctx, &buffer, buffer_size, (const uint8_t **)&frame->data[0], frame->nb_samples);
  45.             ssize_t nbytes = av_samples_get_buffer_size(NULL, codecpar->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
  46.             write(dsp, buffer, nbytes);
  47.         }
  48.         av_packet_unref(pkt);
  49.     }
  50.     av_free(buffer);
  51.     av_frame_free(&frame);
  52.     av_packet_free(&pkt);
  53.     swr_free(&swr_ctx);
  54.     close(dsp);

  55.     avcodec_close(codec_ctx);
  56.     avcodec_free_context(&codec_ctx);
  57.     avformat_close_input(&format_ctx);
  58.     avformat_free_context(format_ctx);
  59.     return 0;
  60. }
复制代码


编译命令
  1. gcc -g -Wall -o main main.c -lavformat -lavcodec -lavutil -lswresample
复制代码


运行
  1. ./main test.mp3
  2. ./main test.mp4
  3. ./main test.aac
  4. ./main test.flv
  5. ...
复制代码


写这个代码参考了下面这些内容,当然肯定不止这些,我没办法全部列出了
https://www.baidu.com/
https://blog.csdn.net/dux003/article/details/5459423
https://www.jianshu.com/p/8ff162ac55bd
https://www.jianshu.com/p/2f2b8e0fe540
https://stackoverflow.com/questi ... float-planar-to-s16
https://cloud.tencent.com/developer/article/1666126
https://blog.csdn.net/woai110120130/article/details/82080648
https://blog.csdn.net/huohongpeng/article/details/119670171
https://www.jb51.net/article/201684.htm
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-9-4 21:46:40 | 显示全部楼层
Windows的程序我也在Mac上运行不了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-5 11:22:53 | 显示全部楼层
mei-mo 发表于 2021-9-4 21:46
Windows的程序我也在Mac上运行不了

我也是

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-5 13:04:55 | 显示全部楼层
mei-mo 发表于 2021-9-4 21:46
Windows的程序我也在Mac上运行不了

可能系统不一样吧
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-5 21:34:22 | 显示全部楼层
mei-mo 发表于 2021-9-4 21:46
Windows的程序我也在Mac上运行不了

你指的是exe吗……
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-6 15:48:12 | 显示全部楼层    本楼为最佳答案   
下面这个代码花了我大概三天的时间,因为学到了很多东西,所以值得,^_^

音频视频处理领域,ffmpeg 大概是最权威的了
ffmpeg 跨平台,mac 肯定能用
我的程序中还使用了 /dev/dsp 设备,不知道 mac 能不能用
这个程序把解码出来的音频数据发往 dsp 设备,如果 dsp 设备不能用,那就使用 sdl,把发往 dsp 的数据发送到 sdl 进行播放
还有,因为使用了 ffmpeg,这个程序可不仅仅支持 mp3,ffmpeg 支持绝大多数的音频视频格式
还有,我刚刚才看到是要求 C++ 写,C语言代码在下面,如果你真的必须是要 C++ 的话,自己改代码吧,^_^
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <sys/ioctl.h>
  6. #include <linux/soundcard.h>
  7. #include <libavformat/avformat.h>
  8. #include <libavcodec/codec.h>
  9. #include <libswresample/swresample.h>

  10. int main(int argc, char *argv[]) {
  11.     if(argc != 2) return -1;
  12.     const char *filename = argv[1];
  13.     AVFormatContext *format_ctx = avformat_alloc_context();
  14.     avformat_open_input(&format_ctx, filename, NULL, NULL);
  15.     avformat_find_stream_info(format_ctx, NULL);
  16.     int stream_idx = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
  17.     AVCodecParameters *codecpar = format_ctx->streams[stream_idx]->codecpar;
  18.     AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
  19.     AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
  20.     avcodec_parameters_to_context(codec_ctx, codecpar);
  21.     avcodec_open2(codec_ctx, codec, NULL);

  22.     int dsp = open("/dev/dsp", O_WRONLY);
  23.     int channels = codecpar->channels;
  24.     int sample_rate = codecpar->sample_rate;
  25.     int sample_fmt = AFMT_S16_LE;   // dsp 有好多格式都不支持,这里使用固定格式,下面把数据转换到这个格式
  26.     ioctl(dsp, SNDCTL_DSP_CHANNELS, &channels);
  27.     ioctl(dsp, SNDCTL_DSP_SPEED, &sample_rate);
  28.     ioctl(dsp, SNDCTL_DSP_SETFMT, &sample_fmt);
  29.     printf("channels: %d, sample_rate: %d, sample_fmt: %d\n", channels, sample_rate,
  30.             av_get_bytes_per_sample(codecpar->format) * 8);
  31.     SwrContext *swr_ctx = swr_alloc();
  32.     int channel_layout = av_get_default_channel_layout(codecpar->channels);     // codecpar->channel_layout 有可能为 0
  33.     swr_alloc_set_opts(swr_ctx, channel_layout, AV_SAMPLE_FMT_S16, codecpar->sample_rate,
  34.             channel_layout, codecpar->format, codecpar->sample_rate, 0, NULL);
  35.     swr_init(swr_ctx);
  36.     AVPacket *pkt = av_packet_alloc();
  37.     AVFrame *frame = av_frame_alloc();
  38.     size_t buffer_size = 48000 * 4;
  39.     uint8_t *buffer = av_malloc(buffer_size);
  40.     while(av_read_frame(format_ctx, pkt) == 0) {
  41.         if(pkt->stream_index == stream_idx) {
  42.             avcodec_send_packet(codec_ctx, pkt);
  43.             avcodec_receive_frame(codec_ctx, frame);
  44.             swr_convert(swr_ctx, &buffer, buffer_size, (const uint8_t **)&frame->data[0], frame->nb_samples);
  45.             ssize_t nbytes = av_samples_get_buffer_size(NULL, codecpar->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
  46.             write(dsp, buffer, nbytes);
  47.         }
  48.         av_packet_unref(pkt);
  49.     }
  50.     av_free(buffer);
  51.     av_frame_free(&frame);
  52.     av_packet_free(&pkt);
  53.     swr_free(&swr_ctx);
  54.     close(dsp);

  55.     avcodec_close(codec_ctx);
  56.     avcodec_free_context(&codec_ctx);
  57.     avformat_close_input(&format_ctx);
  58.     avformat_free_context(format_ctx);
  59.     return 0;
  60. }
复制代码


编译命令
  1. gcc -g -Wall -o main main.c -lavformat -lavcodec -lavutil -lswresample
复制代码


运行
  1. ./main test.mp3
  2. ./main test.mp4
  3. ./main test.aac
  4. ./main test.flv
  5. ...
复制代码


写这个代码参考了下面这些内容,当然肯定不止这些,我没办法全部列出了
https://www.baidu.com/
https://blog.csdn.net/dux003/article/details/5459423
https://www.jianshu.com/p/8ff162ac55bd
https://www.jianshu.com/p/2f2b8e0fe540
https://stackoverflow.com/questi ... float-planar-to-s16
https://cloud.tencent.com/developer/article/1666126
https://blog.csdn.net/woai110120130/article/details/82080648
https://blog.csdn.net/huohongpeng/article/details/119670171
https://www.jb51.net/article/201684.htm
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-10-2 11:29:38 | 显示全部楼层
人造人 发表于 2021-9-6 15:48
下面这个代码花了我大概三天的时间,因为学到了很多东西,所以值得,^_^

音频视频处理领域,ffmpeg 大概 ...

谢谢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-28 16:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表