summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2019-11-16 14:04:22 -0600
committerTimothy Pearson <tpearson@raptorengineering.com>2019-11-16 14:04:22 -0600
commit4c4d573f9986a92aea6fea9febf39665a69f51c1 (patch)
tree45945ad979ba71945e3b1611fb4df79efc4c46de
parent20c5f4d8358e5dab2eb87e611167987a4840122a (diff)
downloadffmpeg-streaming-4c4d573f9986a92aea6fea9febf39665a69f51c1.zip
ffmpeg-streaming-4c4d573f9986a92aea6fea9febf39665a69f51c1.tar.gz
Switch FFmpeg to use raw monotonic timestamps
Use ALSA high resolution hardware timestamps if available
-rw-r--r--libavdevice/alsa.c72
-rw-r--r--libavdevice/alsa.h2
-rw-r--r--libavdevice/alsa_dec.c26
-rw-r--r--libavutil/time.c4
4 files changed, 102 insertions, 2 deletions
diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c
index 117b2ea..10ffe56 100644
--- a/libavdevice/alsa.c
+++ b/libavdevice/alsa.c
@@ -174,6 +174,8 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
snd_pcm_format_t format;
snd_pcm_t *h;
snd_pcm_hw_params_t *hw_params;
+ snd_pcm_sw_params_t *sw_params;
+ snd_pcm_status_t *alsa_pcm_status;
snd_pcm_uframes_t buffer_size, period_size;
uint64_t layout = ctx->streams[0]->codecpar->channel_layout;
@@ -269,6 +271,72 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
goto fail;
}
+ s->use_driver_timestamps = 0;
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 0)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports compat timestamps\n");
+ s->use_driver_timestamps |= 1;
+ }
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 1)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports default timestamps\n");
+ s->use_driver_timestamps |= 2;
+ }
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 2)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports link timestamps\n");
+ s->use_driver_timestamps |= 4;
+ }
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 3)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports link absolute timestamps\n");
+ s->use_driver_timestamps |= 8;
+ }
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 4)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports link estimated timestamps\n");
+ s->use_driver_timestamps |= 16;
+ }
+ if (snd_pcm_hw_params_supports_audio_ts_type(hw_params, 5)) {
+ av_log(ctx, AV_LOG_INFO, "capture device supports link synchronized timestamps\n");
+ s->use_driver_timestamps |= 32;
+ }
+
+ res = snd_pcm_sw_params_malloc(&sw_params);
+ if (res < 0) {
+ av_log(ctx, AV_LOG_ERROR, "cannot allocate software parameter structure (%s)\n",
+ snd_strerror(res));
+ goto fail;
+ }
+
+ res = snd_pcm_sw_params_current(h, sw_params);
+ if (res < 0) {
+ av_log(ctx, AV_LOG_ERROR, "cannot read parameters from device (%s)\n",
+ snd_strerror(res));
+ snd_pcm_sw_params_free(sw_params);
+ goto fail;
+ }
+
+ res = snd_pcm_sw_params_set_tstamp_mode(h, sw_params, SND_PCM_TSTAMP_ENABLE);
+ if (res < 0) {
+ av_log(ctx, AV_LOG_ERROR, "cannot enable timestamps (%s)\n",
+ snd_strerror(res));
+ snd_pcm_sw_params_free(sw_params);
+ goto fail;
+ }
+
+ res = snd_pcm_sw_params_set_tstamp_type(h, sw_params, SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW);
+ if (res < 0) {
+ av_log(ctx, AV_LOG_ERROR, "cannot set timestamp mode (%s)\n",
+ snd_strerror(res));
+ snd_pcm_sw_params_free(sw_params);
+ goto fail;
+ }
+
+ res = snd_pcm_sw_params(h, sw_params);
+ if (res < 0) {
+ av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n",
+ snd_strerror(res));
+ snd_pcm_sw_params_free(sw_params);
+ goto fail;
+ }
+
+ snd_pcm_sw_params_free(sw_params);
snd_pcm_hw_params_free(hw_params);
if (channels > 2 && layout) {
@@ -286,7 +354,10 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
}
}
+ snd_pcm_status_malloc(&alsa_pcm_status);
+
s->h = h;
+ s->st = alsa_pcm_status;
return 0;
fail:
@@ -308,6 +379,7 @@ av_cold int ff_alsa_close(AVFormatContext *s1)
if (CONFIG_ALSA_INDEV)
ff_timefilter_destroy(s->timefilter);
snd_pcm_close(s->h);
+ snd_pcm_status_free(s->st);
return 0;
}
diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h
index 1ed8c82..93fa2d3 100644
--- a/libavdevice/alsa.h
+++ b/libavdevice/alsa.h
@@ -48,6 +48,7 @@ typedef void (*ff_reorder_func)(const void *, void *, int);
typedef struct AlsaData {
AVClass *class;
snd_pcm_t *h;
+ snd_pcm_status_t *st;
int frame_size; ///< bytes per sample * channels
int period_size; ///< preferred size for reads and writes, in frames
int sample_rate; ///< sample rate set by user
@@ -58,6 +59,7 @@ typedef struct AlsaData {
void *reorder_buf;
int reorder_buf_size; ///< in frames
int64_t timestamp; ///< current timestamp, without latency applied.
+ int use_driver_timestamps; ///< bitfield w/ detected driver ts support
} AlsaData;
/**
diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c
index 36494e9..902fba3 100644
--- a/libavdevice/alsa_dec.c
+++ b/libavdevice/alsa_dec.c
@@ -104,6 +104,7 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
int res;
int64_t dts;
snd_pcm_sframes_t delay = 0;
+ snd_pcm_audio_tstamp_config_t tstamp_config;
if (av_new_packet(pkt, s->period_size * s->frame_size) < 0) {
return AVERROR(EIO);
@@ -125,8 +126,29 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
ff_timefilter_reset(s->timefilter);
}
- dts = av_gettime();
- snd_pcm_delay(s->h, &delay);
+ dts = 0;
+ if (s->use_driver_timestamps) {
+ tstamp_config.type_requested = 1;
+ tstamp_config.report_delay = 1;
+ snd_pcm_status_set_audio_htstamp_config(s->st, &tstamp_config);
+ if (snd_pcm_status(s->h, s->st) >= 0) {
+ struct timespec ts;
+ snd_pcm_status_get_driver_htstamp(s->st, &ts);
+ if ((ts.tv_sec == 0) && (ts.tv_nsec == 0)) {
+ // Try alternate access method
+ snd_pcm_status_get_htstamp(s->st, &ts);
+ }
+ dts = (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+ delay = snd_pcm_status_get_delay(s->st);
+ }
+ }
+ if (dts == 0) {
+ // Driver timestamps not supported
+ // Fall back to system timestamps
+ dts = av_gettime();
+ snd_pcm_delay(s->h, &delay);
+ }
+
dts -= av_rescale(delay + res, 1000000, s->sample_rate);
pkt->pts = ff_timefilter_update(s->timefilter, dts, s->last_period);
s->last_period = res;
diff --git a/libavutil/time.c b/libavutil/time.c
index afa6658..9cc1898 100644
--- a/libavutil/time.c
+++ b/libavutil/time.c
@@ -61,7 +61,11 @@ int64_t av_gettime_relative(void)
#endif
{
struct timespec ts;
+#if defined(CLOCK_MONOTONIC_RAW)
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+#else
clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
}
#endif
OpenPOWER on IntegriCloud