基于 libmad 的简单 MP3 流媒体播放器的实现(3)
- UID
- 1066743
|
基于 libmad 的简单 MP3 流媒体播放器的实现(3)
清单 7:PCM 数据写入声卡函数实现例程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
| while (nsamples--) {
/* nsamples 是采样的数目 */
signed int sample;
sample = pcm->samples[0][j];
*(OutputPtr++) = sample & 0xff;
*(OutputPtr++) = (sample >> 8);
*(OutputPtr++) = (sample >> 16);
*(OutputPtr++) = (sample >> 24);
if (nchannels == 2) {
sample = pcm->samples[1][j];
*(OutputPtr++) = sample & 0xff;
*(OutputPtr++) = sample >> 8;
*(OutputPtr++) = (sample >> 16);
*(OutputPtr++) = (sample >> 24);
}
j++;
}
if ((err = snd_pcm_writei (playback_handle, buf, samples)) < 0) {
err = xrun_recovery(playback_handle, err);
if (err < 0) {
printf("Write error: %s\n", snd_strerror(err));
return -1;
}
}
|
这里用到了 关于 ALSA 文档中的例子函数 xrun_recovery( )。详细例子请参见 。使用此函数的目的是避免出现由于网络原因,声卡不能及时得到音频数据而使得 snd_pcm_writei() 不能正常连续工作。实际上在 xrun_recovery( ) 中,又调用 snd_pcm_prepare() 和 snd_pcm_resume() 以实现能“恢复错误”的功能。-EPIPE 错误表示应用程序没有及时把 PCM 采样数据送入ASLA 库。xrun_recovery() 函数如下所示:
清单 8:xrun_recovery() 函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| int xrun_recovery(snd_pcm_t *handle, int err)
{
if (err == -EPIPE) { /* under-run */
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from underrun, prepare failed: %s\n",
snd_strerror(err));
return 0;
} else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(handle)) == -EAGAIN)
sleep(1); /* wait until the suspend flag is released */
if (err < 0) {
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from suspend, prepare failed: %s\n",
snd_strerror(err));
}
return 0;
}
return err;
}
|
知道了具体的音频设备操作方法,就该使用 MAD 提供的函数具体实现解码了。函数 mp3_decode_buf( ) 提供了使用 libmad 解码的方法。首先调用 mad_stream_buffer() 函数把 MP3 流数据和 decode_stream 关联,然后开始循环解码数据。如果在解码数据过程中,有不完整 PCM 数据帧,那么 decode_stream.error 的值就是 MAD_ERROR_BUFLEN,且 decode_stream.next_frame 不为 NULL。这时候,把剩余的未解码的数据再拷贝到数据解码缓冲区里。 mad_frame_decode( ) 函数从 decode_stream 中得到 PCM 数据。
清单 9:mad_frame_decode( ) 函数从 decode_stream 中得到 PCM 数据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
| int mp3_decode_buf(char *input_buf, int size)
{
int decode_over_flag = 0;
int remain_bytes = 0;
int ret_val = 0;
mad_stream_buffer(&decode_stream, input_buf, size);
decode_stream.error = MAD_ERROR_NONE;
while (1)
{
if (decode_stream.error == MAD_ERROR_BUFLEN) {
if (decode_stream.next_frame != NULL) {
remain_bytes = decode_stream.bufend - decode_stream.next_frame;
memcpy(input_buf, decode_stream.next_frame, remain_bytes);
return remain_bytes;
}
}
ret_val = mad_frame_decode(&decode_frame, &decode_stream);
/* 省略部分代码 */
...
if (ret_val == 0) {
if (play_frame(&decode_frame) == -1) {
return -1;
}
}
/* 后面代码省略 */
...
}
return 0;
}
|
|
|
|
|
|
|