ffplay: more precise audio clock based on current time

Since SDL has no audio buffer fullness info, one can get a much precise audio
clock based on the last time of the audio callback and the elapsed time since.

To achieve this I introduced the audio_current_pts and audio_current_pts_drift
variables (similar to video_current_pts and video_current_pts_drift) and
calculate them in the end of the audio callback, when VideoState->audio_clock
is already updated. The reference time I use is from the start of the audio
callback, because this way the amount of time used for audio decoding is not
interfereing with calculation.

I also replaced the audio_write_get_buf_size function with a calculated
variable because when the audio frame decoding is in progress audio_buf_size
and audio_buf_index are not stable, so using them from other threads are not a
good idea.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Marton Balint 2011-08-14 20:21:25 +02:00 committed by Michael Niedermayer
parent abf6b0d1ea
commit 10b7b4a6a1

View File

@ -158,10 +158,13 @@ typedef struct VideoState {
uint8_t *audio_buf;
unsigned int audio_buf_size; /* in bytes */
int audio_buf_index; /* in bytes */
int audio_write_buf_size;
AVPacket audio_pkt_temp;
AVPacket audio_pkt;
enum AVSampleFormat audio_src_fmt;
AVAudioConvert *reformat_ctx;
double audio_current_pts;
double audio_current_pts_drift;
enum ShowMode {
SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
@ -706,13 +709,6 @@ static void video_image_display(VideoState *is)
}
}
/* get the current audio output buffer size, in samples. With SDL, we
cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
{
return is->audio_buf_size - is->audio_buf_index;
}
static inline int compute_mod(int a, int b)
{
return a < 0 ? a%b + b : a%b;
@ -735,7 +731,7 @@ static void video_audio_display(VideoState *s)
if (!s->paused) {
int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
n = 2 * channels;
delay = audio_write_get_buf_size(s);
delay = s->audio_write_buf_size;
delay /= n;
/* to be more precise, we take into account the time spent since
@ -989,18 +985,11 @@ static int refresh_thread(void *opaque)
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
double pts;
int hw_buf_size, bytes_per_sec;
pts = is->audio_clock;
hw_buf_size = audio_write_get_buf_size(is);
bytes_per_sec = 0;
if (is->audio_st) {
bytes_per_sec = is->audio_st->codec->sample_rate *
2 * is->audio_st->codec->channels;
if (is->paused) {
return is->audio_current_pts;
} else {
return is->audio_current_pts_drift + av_gettime() / 1000000.0;
}
if (bytes_per_sec)
pts -= (double)hw_buf_size / bytes_per_sec;
return pts;
}
/* get the current video clock value */
@ -2074,6 +2063,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
VideoState *is = opaque;
int audio_size, len1;
int bytes_per_sec;
double pts;
audio_callback_time = av_gettime();
@ -2103,6 +2093,12 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
stream += len1;
is->audio_buf_index += len1;
}
bytes_per_sec = is->audio_st->codec->sample_rate *
2 * is->audio_st->codec->channels;
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. */
is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
}
/* open a given stream. Return 0 if OK */