#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;
}