-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathAudioPlayer.cpp
More file actions
173 lines (138 loc) · 5.09 KB
/
AudioPlayer.cpp
File metadata and controls
173 lines (138 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "AudioPlayer.h"
using std::operator""ms;
const AVSampleFormat requireAudioFmt = AV_SAMPLE_FMT_S32; // SDL only accpet interleaved audio data.
void AudioPlayer::OpenDevice() {
audioFormatCtx = nullptr;
int ret = avformat_open_input(&audioFormatCtx, filepath.c_str(), nullptr, nullptr);
if (ret != 0) {
throw std::runtime_error("can not open input format!");
}
ret = avformat_find_stream_info(audioFormatCtx, nullptr);
if (ret < 0) {
throw std::runtime_error("fail to find stream info.");
}
for (uint16_t i = 0; i < audioFormatCtx->nb_streams; i++) {
if (audioFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audioStream = audioFormatCtx->streams[i];
break;
}
}
if (audioStream == nullptr) {
throw std::runtime_error("fail to find stream.");
}
AVCodec * audioCodec = avcodec_find_decoder(audioStream->codecpar->codec_id);
audioCodecCtx = avcodec_alloc_context3(audioCodec);
avcodec_parameters_to_context(audioCodecCtx, audioStream->codecpar);
if (avcodec_open2(audioCodecCtx, audioCodec, nullptr) < 0) {
throw std::runtime_error("fail to open codec.");
}
// config Converter
audioConverter = swr_alloc_set_opts(nullptr,
av_get_default_channel_layout(audioCodecCtx->channels),
requireAudioFmt, // aac encoder only receive this format
audioCodecCtx->sample_rate,
av_get_default_channel_layout(audioCodecCtx->channels),
(AVSampleFormat)audioStream->codecpar->format,
audioStream->codecpar->sample_rate,
0, nullptr);
swr_init(audioConverter);
isRun = true;
isPlayFinish = false;
}
void AudioPlayer::PlayAndDecode()
{
SdlAudio();
AVPacket *packet_in = av_packet_alloc();
AVFrame *frame_out = av_frame_alloc();
int ret;
while (isRun) {
ret = av_read_frame(audioFormatCtx, packet_in);
if (ret < 0) {
isRun = false;
break; //throw std::runtime_error("fail to read frame frome file.");
}
ret = avcodec_send_packet(audioCodecCtx, packet_in);
if (ret < 0) throw std::runtime_error("fail to send packet in decode");
ret = avcodec_receive_frame(audioCodecCtx, frame_out); //frame_out->format must be FLTP for aac
if (ret < 0) throw std::runtime_error("fail to receive frame in decode");
av_packet_unref(packet_in);
// transform audio format.
uint8_t **cSamples = nullptr;
ret = av_samples_alloc_array_and_samples(&cSamples, nullptr, audioCodecCtx->channels, frame_out->nb_samples, requireAudioFmt, 0);
if (ret < 0) {
throw std::runtime_error("Fail to alloc samples by av_samples_alloc_array_and_samples.");
}
ret = swr_convert(audioConverter, cSamples, frame_out->nb_samples, (const uint8_t**)frame_out->extended_data, frame_out->nb_samples);
if (ret < 0) {
throw std::runtime_error("Fail to swr_convert.");
}
//100 packet is about 2s
while (fifo.size()>100) {
std::this_thread::sleep_for(500ms);
}
lock.lock();
fifo.push(cSamples);
lock.unlock();
av_frame_unref(frame_out);
}
av_packet_free(&packet_in);
av_frame_free(&frame_out);
while (!isPlayFinish) {
std::this_thread::sleep_for(100ms);
}
}
void AudioPlayer::GetData(uint8_t * buf, int len)
{
memset(buf, 0, len);
lock.lock();
if (!fifo.empty()) {
uint8_t ** data = fifo.front();
fifo.pop();
lock.unlock();
memcpy(buf, data[0], len);
av_freep(&data[0]);
}
else {
lock.unlock();
if (!isRun) {
SDL_PauseAudio(1);
puts("Play Finish.");
isPlayFinish = true;
}
}
}
void fill_audio(void *udata, Uint8 *stream, int len) {
auto decoder = (AudioPlayer*)udata;
decoder->GetData(stream, len);
}
void AudioPlayer::SdlAudio()
{
if (SDL_Init(SDL_INIT_AUDIO)) {
throw std::runtime_error("fail to init SDL.");
}
SDL_memset(&wanted_spec, 0, sizeof(wanted_spec));
wanted_spec.freq = audioStream->codecpar->sample_rate;
wanted_spec.format = AUDIO_S32SYS;
wanted_spec.channels = audioStream->codecpar->channels;
wanted_spec.silence = 0;
wanted_spec.samples = 1024; // samples per channel. It equals to frame->nb_samples.
wanted_spec.callback = fill_audio;
wanted_spec.userdata = this;
if (SDL_OpenAudio(&wanted_spec, nullptr) != 0) {
throw std::runtime_error("fail to open audio device in SDL.");
}
SDL_PauseAudio(0);
}
void AudioPlayer::Close()
{
SDL_CloseAudio();
avformat_close_input(&audioFormatCtx);
avcodec_free_context(&audioCodecCtx);
swr_free(&audioConverter);
while (!fifo.empty()) {
uint8_t** a = fifo.front();
fifo.pop();
av_freep(&a[0]);
}
puts("Close AudioPlayer.");
}