/* prepare a new audio buffer */
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) {
VideoState *is = opaque;
int audio_size, len1;
int bytes_per_sec;
int frame_size = av_samples_get_buffer_size(NULL, is->audio_tgt_channels, 1,
is->audio_tgt_fmt, 1);
double pts;
audio_callback_time = av_gettime();//当前正在播放的声音的系统时间
LOGV("audio_buffer:audio_callback_time=%03f,len=%d\n",audio_callback_time/1000000.0,len);
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
audio_size = audio_decode_frame(is, &pts);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = is->silence_buf;
is->audio_buf_size = sizeof(is->silence_buf) / frame_size
* frame_size;
} else {
if (is->show_mode != SHOW_MODE_VIDEO)
update_sample_display(is, (int16_t *) is->audio_buf,
audio_size);
is->audio_buf_size = audio_size;
}
is->audio_buf_index = 0;
}
len1 = is->audio_buf_size - is->audio_buf_index;
if (len1 > len)
len1 = len;
memcpy(stream, (uint8_t *) is->audio_buf + is->audio_buf_index, len1);
len -= len1;
stream += len1;
is->audio_buf_index += len1;
}
bytes_per_sec = is->audio_tgt_freq * is->audio_tgt_channels
* av_get_bytes_per_sample(is->audio_tgt_fmt);
is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
/* Let's assume the audio driver that is used by SDL has two periods. */
//从当前播放的声音开始到播放完两个stream buffer和上次未传递完的音频帧字节(当stream buffer为自定义buffer的1.5倍时,每次未
//传完的大小为0.5自定义buffer)才能到当前解码后的音频帧 ,所以以下可以获取到当前播放声音的pts
is->audio_current_pts = is->audio_clock
- (double) (2 * is->audio_hw_buf_size + is->audio_write_buf_size)
/ bytes_per_sec;
LOGV("audio_buffer: is->audio_hw_buf_size =%d,audio_size=%d,delay=%03fis->audio_current_pts = %03f is->audio_write_buf_size=%d\n",is->audio_hw_buf_size,audio_size,(av_gettime()-audio_callback_time)/1000000.0,
is->audio_current_pts, is->audio_write_buf_size);
//现在已经获取到当前播放声音对应的系统时间 audio_callback_time 和audio_current_pts,它们之差对应的应该是个固定的偏移值,
//否则说明声音播放过快或者过慢(不要被drift迷惑,可能是以前版本的遗留症)
is->audio_current_pts_drift = is->audio_current_pts
- audio_callback_time / 1000000.0;
}
static double get_audio_clock(VideoState *is) {
if (is->paused) {
return is->audio_current_pts;
} else {
//因为从sdl_audio_callback回调开始时播放的声音已经持续了一段时间,用当时的pts+播放持续的时间得到声音的参考时钟此刻
//的值, is->audio_current_pts +(av_gettime() / 1000000.0-audio_callback_time / 1000000.0)
return is->audio_current_pts_drift + av_gettime() / 1000000.0;
}
}
以上是我对ffplay.c中以音频为参考时钟的个人理解,不足之处希望大家相互指点。
ffplay中音频参考时钟的获取
最新推荐文章于 2024-01-31 20:29:35 发布