|
发表于 2021-9-6 15:48:12
|
显示全部楼层
本楼为最佳答案
 下面这个代码花了我大概三天的时间,因为学到了很多东西,所以值得,^_^
音频视频处理领域,ffmpeg 大概是最权威的了
ffmpeg 跨平台,mac 肯定能用
我的程序中还使用了 /dev/dsp 设备,不知道 mac 能不能用
这个程序把解码出来的音频数据发往 dsp 设备,如果 dsp 设备不能用,那就使用 sdl,把发往 dsp 的数据发送到 sdl 进行播放
还有,因为使用了 ffmpeg,这个程序可不仅仅支持 mp3,ffmpeg 支持绝大多数的音频视频格式
还有,我刚刚才看到是要求 C++ 写,C语言代码在下面,如果你真的必须是要 C++ 的话,自己改代码吧,^_^
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <linux/soundcard.h>
- #include <libavformat/avformat.h>
- #include <libavcodec/codec.h>
- #include <libswresample/swresample.h>
- int main(int argc, char *argv[]) {
- if(argc != 2) return -1;
- const char *filename = argv[1];
- AVFormatContext *format_ctx = avformat_alloc_context();
- avformat_open_input(&format_ctx, filename, NULL, NULL);
- avformat_find_stream_info(format_ctx, NULL);
- int stream_idx = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
- AVCodecParameters *codecpar = format_ctx->streams[stream_idx]->codecpar;
- AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
- AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
- avcodec_parameters_to_context(codec_ctx, codecpar);
- avcodec_open2(codec_ctx, codec, NULL);
- int dsp = open("/dev/dsp", O_WRONLY);
- int channels = codecpar->channels;
- int sample_rate = codecpar->sample_rate;
- int sample_fmt = AFMT_S16_LE; // dsp 有好多格式都不支持,这里使用固定格式,下面把数据转换到这个格式
- ioctl(dsp, SNDCTL_DSP_CHANNELS, &channels);
- ioctl(dsp, SNDCTL_DSP_SPEED, &sample_rate);
- ioctl(dsp, SNDCTL_DSP_SETFMT, &sample_fmt);
- printf("channels: %d, sample_rate: %d, sample_fmt: %d\n", channels, sample_rate,
- av_get_bytes_per_sample(codecpar->format) * 8);
- SwrContext *swr_ctx = swr_alloc();
- int channel_layout = av_get_default_channel_layout(codecpar->channels); // codecpar->channel_layout 有可能为 0
- swr_alloc_set_opts(swr_ctx, channel_layout, AV_SAMPLE_FMT_S16, codecpar->sample_rate,
- channel_layout, codecpar->format, codecpar->sample_rate, 0, NULL);
- swr_init(swr_ctx);
- AVPacket *pkt = av_packet_alloc();
- AVFrame *frame = av_frame_alloc();
- size_t buffer_size = 48000 * 4;
- uint8_t *buffer = av_malloc(buffer_size);
- while(av_read_frame(format_ctx, pkt) == 0) {
- if(pkt->stream_index == stream_idx) {
- avcodec_send_packet(codec_ctx, pkt);
- avcodec_receive_frame(codec_ctx, frame);
- swr_convert(swr_ctx, &buffer, buffer_size, (const uint8_t **)&frame->data[0], frame->nb_samples);
- ssize_t nbytes = av_samples_get_buffer_size(NULL, codecpar->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
- write(dsp, buffer, nbytes);
- }
- av_packet_unref(pkt);
- }
- av_free(buffer);
- av_frame_free(&frame);
- av_packet_free(&pkt);
- swr_free(&swr_ctx);
- close(dsp);
- avcodec_close(codec_ctx);
- avcodec_free_context(&codec_ctx);
- avformat_close_input(&format_ctx);
- avformat_free_context(format_ctx);
- return 0;
- }
复制代码
编译命令
- gcc -g -Wall -o main main.c -lavformat -lavcodec -lavutil -lswresample
复制代码
运行
- ./main test.mp3
- ./main test.mp4
- ./main test.aac
- ./main test.flv
- ...
复制代码
写这个代码参考了下面这些内容,当然肯定不止这些,我没办法全部列出了
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 |
|