00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00048 #include <alsa/asoundlib.h>
00049 #include "libavformat/avformat.h"
00050 #include "libavformat/internal.h"
00051 #include "libavutil/opt.h"
00052
00053 #include "alsa-audio.h"
00054
00055 static av_cold int audio_read_header(AVFormatContext *s1,
00056 AVFormatParameters *ap)
00057 {
00058 AlsaData *s = s1->priv_data;
00059 AVStream *st;
00060 int ret;
00061 enum CodecID codec_id;
00062 snd_pcm_sw_params_t *sw_params;
00063
00064 st = avformat_new_stream(s1, NULL);
00065 if (!st) {
00066 av_log(s1, AV_LOG_ERROR, "Cannot add stream\n");
00067
00068 return AVERROR(ENOMEM);
00069 }
00070 codec_id = s1->audio_codec_id;
00071
00072 ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels,
00073 &codec_id);
00074 if (ret < 0) {
00075 return AVERROR(EIO);
00076 }
00077
00078 if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW)
00079 av_log(s1, AV_LOG_WARNING,
00080 "capture with some ALSA plugins, especially dsnoop, "
00081 "may hang.\n");
00082
00083 ret = snd_pcm_sw_params_malloc(&sw_params);
00084 if (ret < 0) {
00085 av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n",
00086 snd_strerror(ret));
00087 goto fail;
00088 }
00089
00090 snd_pcm_sw_params_current(s->h, sw_params);
00091 snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE);
00092
00093 ret = snd_pcm_sw_params(s->h, sw_params);
00094 snd_pcm_sw_params_free(sw_params);
00095 if (ret < 0) {
00096 av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n",
00097 snd_strerror(ret));
00098 goto fail;
00099 }
00100
00101
00102 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00103 st->codec->codec_id = codec_id;
00104 st->codec->sample_rate = s->sample_rate;
00105 st->codec->channels = s->channels;
00106 avpriv_set_pts_info(st, 64, 1, 1000000);
00107
00108 return 0;
00109
00110 fail:
00111 snd_pcm_close(s->h);
00112 return AVERROR(EIO);
00113 }
00114
00115 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
00116 {
00117 AlsaData *s = s1->priv_data;
00118 AVStream *st = s1->streams[0];
00119 int res;
00120 snd_htimestamp_t timestamp;
00121 snd_pcm_uframes_t ts_delay;
00122
00123 if (av_new_packet(pkt, s->period_size) < 0) {
00124 return AVERROR(EIO);
00125 }
00126
00127 while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) {
00128 if (res == -EAGAIN) {
00129 av_free_packet(pkt);
00130
00131 return AVERROR(EAGAIN);
00132 }
00133 if (ff_alsa_xrun_recover(s1, res) < 0) {
00134 av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n",
00135 snd_strerror(res));
00136 av_free_packet(pkt);
00137
00138 return AVERROR(EIO);
00139 }
00140 }
00141
00142 snd_pcm_htimestamp(s->h, &ts_delay, ×tamp);
00143 ts_delay += res;
00144 pkt->pts = timestamp.tv_sec * 1000000LL
00145 + (timestamp.tv_nsec * st->codec->sample_rate
00146 - ts_delay * 1000000000LL + st->codec->sample_rate * 500LL)
00147 / (st->codec->sample_rate * 1000LL);
00148
00149 pkt->size = res * s->frame_size;
00150
00151 return 0;
00152 }
00153
00154 static const AVOption options[] = {
00155 { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.dbl = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
00156 { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.dbl = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
00157 { NULL },
00158 };
00159
00160 static const AVClass alsa_demuxer_class = {
00161 .class_name = "ALSA demuxer",
00162 .item_name = av_default_item_name,
00163 .option = options,
00164 .version = LIBAVUTIL_VERSION_INT,
00165 };
00166
00167 AVInputFormat ff_alsa_demuxer = {
00168 .name = "alsa",
00169 .long_name = NULL_IF_CONFIG_SMALL("ALSA audio input"),
00170 .priv_data_size = sizeof(AlsaData),
00171 .read_header = audio_read_header,
00172 .read_packet = audio_read_packet,
00173 .read_close = ff_alsa_close,
00174 .flags = AVFMT_NOFILE,
00175 .priv_class = &alsa_demuxer_class,
00176 };