aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas George <nicolas.george@normalesup.org>2011-07-01 15:26:40 +0200
committerNicolas George <nicolas.george@normalesup.org>2011-07-02 10:43:38 +0200
commit5d35b279e21814b3b1499ae0b2e0e0dad7d7f782 (patch)
tree1a4a710cd1c0221436692f4a2879cac4e019a0fc
parent3074f03a074de3aab79639d261cbd0ccc265b5b4 (diff)
downloadffmpeg-5d35b279e21814b3b1499ae0b2e0e0dad7d7f782.tar.gz
ALSA demuxer: use av_gettime and a timefilter.
The PTS for captured audio was measured using snd_pcm_htimestamp. snd_pcm_htimestamp hangs when the input is a dsnoop plugin. Furthermore, at some point, snd_pcm_htimestamp started returning monotonic timestamps rather than wall clock timestamps, in most but not all situations. Monotonic timestamps are fine, but ffmpeg uses wall clock timestamps everywhere else, and we have no API to inform the user which kind of timestamps it is. A separate snd_pcm_htimestamp is only slightly less accurate than snd_pcm_htimestamp: the standard deviation for the difference between two consecutive timestamps is (on my hardware): - ~13 µs with snd_pcm_htimestamp; - ~35 µs with av_gettime; - ~5 µs with av_gettime and a timefilter.
-rw-r--r--libavdevice/alsa-audio-common.c1
-rw-r--r--libavdevice/alsa-audio-dec.c44
-rw-r--r--libavdevice/alsa-audio.h2
-rw-r--r--libavformat/Makefile1
4 files changed, 17 insertions, 31 deletions
diff --git a/libavdevice/alsa-audio-common.c b/libavdevice/alsa-audio-common.c
index 8c5be3c864..6188721f48 100644
--- a/libavdevice/alsa-audio-common.c
+++ b/libavdevice/alsa-audio-common.c
@@ -316,6 +316,7 @@ av_cold int ff_alsa_close(AVFormatContext *s1)
AlsaData *s = s1->priv_data;
av_freep(&s->reorder_buf);
+ ff_timefilter_destroy(s->timefilter);
snd_pcm_close(s->h);
return 0;
}
diff --git a/libavdevice/alsa-audio-dec.c b/libavdevice/alsa-audio-dec.c
index e3ad98b7f3..f8977a10f9 100644
--- a/libavdevice/alsa-audio-dec.c
+++ b/libavdevice/alsa-audio-dec.c
@@ -59,6 +59,7 @@ static av_cold int audio_read_header(AVFormatContext *s1,
int ret;
enum CodecID codec_id;
snd_pcm_sw_params_t *sw_params;
+ double o;
#if FF_API_FORMAT_PARAMETERS
if (ap->sample_rate > 0)
@@ -82,35 +83,17 @@ static av_cold int audio_read_header(AVFormatContext *s1,
return AVERROR(EIO);
}
- if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW)
- av_log(s1, AV_LOG_WARNING,
- "capture with some ALSA plugins, especially dsnoop, "
- "may hang.\n");
-
- ret = snd_pcm_sw_params_malloc(&sw_params);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n",
- snd_strerror(ret));
- goto fail;
- }
-
- snd_pcm_sw_params_current(s->h, sw_params);
- snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE);
-
- ret = snd_pcm_sw_params(s->h, sw_params);
- snd_pcm_sw_params_free(sw_params);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n",
- snd_strerror(ret));
- goto fail;
- }
-
/* take real parameters */
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = codec_id;
st->codec->sample_rate = s->sample_rate;
st->codec->channels = s->channels;
av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+ o = 2 * M_PI * s->period_size / s->sample_rate * 1.5; // bandwidth: 1.5Hz
+ s->timefilter = ff_timefilter_new(1000000.0 / s->sample_rate,
+ sqrt(2 * o), o * o);
+ if (!s->timefilter)
+ goto fail;
return 0;
@@ -124,8 +107,8 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
AlsaData *s = s1->priv_data;
AVStream *st = s1->streams[0];
int res;
- snd_htimestamp_t timestamp;
- snd_pcm_uframes_t ts_delay;
+ int64_t dts;
+ snd_pcm_sframes_t delay = 0;
if (av_new_packet(pkt, s->period_size * s->frame_size) < 0) {
return AVERROR(EIO);
@@ -144,14 +127,13 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
return AVERROR(EIO);
}
+ ff_timefilter_reset(s->timefilter);
}
- snd_pcm_htimestamp(s->h, &ts_delay, &timestamp);
- ts_delay += res;
- pkt->pts = timestamp.tv_sec * 1000000LL
- + (timestamp.tv_nsec * st->codec->sample_rate
- - ts_delay * 1000000000LL + st->codec->sample_rate * 500LL)
- / (st->codec->sample_rate * 1000LL);
+ 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, res);
pkt->size = res * s->frame_size;
diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h
index 9b1ecb1696..0226632479 100644
--- a/libavdevice/alsa-audio.h
+++ b/libavdevice/alsa-audio.h
@@ -33,6 +33,7 @@
#include <alsa/asoundlib.h>
#include "config.h"
#include "libavutil/log.h"
+#include "libavformat/timefilter.h"
#include "avdevice.h"
/* XXX: we make the assumption that the soundcard accepts this format */
@@ -49,6 +50,7 @@ typedef struct {
int period_size; ///< preferred size for reads and writes, in frames
int sample_rate; ///< sample rate set by user
int channels; ///< number of channels set by user
+ TimeFilter *timefilter;
void (*reorder_func)(const void *, void *, int);
void *reorder_buf;
int reorder_buf_size; ///< in frames
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 3d9017b3e4..6d7a342c9e 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -338,6 +338,7 @@ OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
# libavdevice dependencies
+OBJS-$(CONFIG_ALSA_INDEV) += timefilter.o
OBJS-$(CONFIG_JACK_INDEV) += timefilter.o
TESTPROGS = timefilter