Libav 0.7.1
|
00001 /* 00002 * ALSA input and output 00003 * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) 00004 * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) 00005 * 00006 * This file is part of Libav. 00007 * 00008 * Libav is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * Libav is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with Libav; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00048 #include <alsa/asoundlib.h> 00049 #include "libavformat/avformat.h" 00050 #include "libavutil/opt.h" 00051 00052 #include "alsa-audio.h" 00053 00054 static av_cold int audio_read_header(AVFormatContext *s1, 00055 AVFormatParameters *ap) 00056 { 00057 AlsaData *s = s1->priv_data; 00058 AVStream *st; 00059 int ret; 00060 enum CodecID codec_id; 00061 snd_pcm_sw_params_t *sw_params; 00062 00063 #if FF_API_FORMAT_PARAMETERS 00064 if (ap->sample_rate > 0) 00065 s->sample_rate = ap->sample_rate; 00066 00067 if (ap->channels > 0) 00068 s->channels = ap->channels; 00069 #endif 00070 00071 st = av_new_stream(s1, 0); 00072 if (!st) { 00073 av_log(s1, AV_LOG_ERROR, "Cannot add stream\n"); 00074 00075 return AVERROR(ENOMEM); 00076 } 00077 codec_id = s1->audio_codec_id; 00078 00079 ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels, 00080 &codec_id); 00081 if (ret < 0) { 00082 return AVERROR(EIO); 00083 } 00084 00085 if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW) 00086 av_log(s1, AV_LOG_WARNING, 00087 "capture with some ALSA plugins, especially dsnoop, " 00088 "may hang.\n"); 00089 00090 ret = snd_pcm_sw_params_malloc(&sw_params); 00091 if (ret < 0) { 00092 av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n", 00093 snd_strerror(ret)); 00094 goto fail; 00095 } 00096 00097 snd_pcm_sw_params_current(s->h, sw_params); 00098 snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE); 00099 00100 ret = snd_pcm_sw_params(s->h, sw_params); 00101 snd_pcm_sw_params_free(sw_params); 00102 if (ret < 0) { 00103 av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n", 00104 snd_strerror(ret)); 00105 goto fail; 00106 } 00107 00108 /* take real parameters */ 00109 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00110 st->codec->codec_id = codec_id; 00111 st->codec->sample_rate = s->sample_rate; 00112 st->codec->channels = s->channels; 00113 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ 00114 00115 return 0; 00116 00117 fail: 00118 snd_pcm_close(s->h); 00119 return AVERROR(EIO); 00120 } 00121 00122 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) 00123 { 00124 AlsaData *s = s1->priv_data; 00125 AVStream *st = s1->streams[0]; 00126 int res; 00127 snd_htimestamp_t timestamp; 00128 snd_pcm_uframes_t ts_delay; 00129 00130 if (av_new_packet(pkt, s->period_size) < 0) { 00131 return AVERROR(EIO); 00132 } 00133 00134 while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) { 00135 if (res == -EAGAIN) { 00136 av_free_packet(pkt); 00137 00138 return AVERROR(EAGAIN); 00139 } 00140 if (ff_alsa_xrun_recover(s1, res) < 0) { 00141 av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n", 00142 snd_strerror(res)); 00143 av_free_packet(pkt); 00144 00145 return AVERROR(EIO); 00146 } 00147 } 00148 00149 snd_pcm_htimestamp(s->h, &ts_delay, ×tamp); 00150 ts_delay += res; 00151 pkt->pts = timestamp.tv_sec * 1000000LL 00152 + (timestamp.tv_nsec * st->codec->sample_rate 00153 - ts_delay * 1000000000LL + st->codec->sample_rate * 500LL) 00154 / (st->codec->sample_rate * 1000LL); 00155 00156 pkt->size = res * s->frame_size; 00157 00158 return 0; 00159 } 00160 00161 static const AVOption options[] = { 00162 { "sample_rate", "", offsetof(AlsaData, sample_rate), FF_OPT_TYPE_INT, {.dbl = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, 00163 { "channels", "", offsetof(AlsaData, channels), FF_OPT_TYPE_INT, {.dbl = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, 00164 { NULL }, 00165 }; 00166 00167 static const AVClass alsa_demuxer_class = { 00168 .class_name = "ALSA demuxer", 00169 .item_name = av_default_item_name, 00170 .option = options, 00171 .version = LIBAVUTIL_VERSION_INT, 00172 }; 00173 00174 AVInputFormat ff_alsa_demuxer = { 00175 "alsa", 00176 NULL_IF_CONFIG_SMALL("ALSA audio input"), 00177 sizeof(AlsaData), 00178 NULL, 00179 audio_read_header, 00180 audio_read_packet, 00181 ff_alsa_close, 00182 .flags = AVFMT_NOFILE, 00183 .priv_class = &alsa_demuxer_class, 00184 };