/*
* Linux audio play and grab interface
- * Copyright (c) 2000, 2001 Gerard Lantau.
+ * Copyright (c) 2000, 2001 Fabrice Bellard.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
+ * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "avformat.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <linux/soundcard.h>
+#include <sys/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int channels;
int frame_size; /* in bytes ! */
int codec_id;
+ int flip_left : 1;
UINT8 buffer[AUDIO_BLOCK_SIZE];
int buffer_ptr;
} AudioData;
{
int audio_fd;
int tmp, err;
+ char *flip = getenv("AUDIO_FLIP_LEFT");
/* open linux audio device */
if (is_output)
return -EIO;
}
+ if (flip && *flip == '1') {
+ s->flip_left = 1;
+ }
+
/* non blocking mode */
- fcntl(audio_fd, F_SETFL, O_NONBLOCK);
+ if (!is_output)
+ fcntl(audio_fd, F_SETFL, O_NONBLOCK);
s->frame_size = AUDIO_BLOCK_SIZE;
#if 0
perror("SNDCTL_DSP_STEREO");
goto fail;
}
+ if (tmp)
+ s->channels = 2;
tmp = s->sample_rate;
err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
/* sound output support */
static int audio_write_header(AVFormatContext *s1)
{
- AudioData *s;
+ AudioData *s = s1->priv_data;
AVStream *st;
int ret;
- s = av_mallocz(sizeof(AudioData));
- if (!s)
- return -ENOMEM;
- s1->priv_data = s;
-
st = s1->streams[0];
s->sample_rate = st->codec.sample_rate;
s->channels = st->codec.channels;
ret = audio_open(s, 1);
if (ret < 0) {
- free(s);
return -EIO;
} else {
return 0;
if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
for(;;) {
ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
- if (ret != 0)
+ if (ret > 0)
break;
if (ret < 0 && (errno != EAGAIN && errno != EINTR))
return -EIO;
AudioData *s = s1->priv_data;
audio_close(s);
- free(s);
return 0;
}
static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
- AudioData *s;
+ AudioData *s = s1->priv_data;
AVStream *st;
int ret;
if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
return -1;
- s = av_mallocz(sizeof(AudioData));
- if (!s)
- return -ENOMEM;
- st = av_mallocz(sizeof(AVStream));
+ st = av_new_stream(s1, 0);
if (!st) {
- free(s);
return -ENOMEM;
}
- s1->priv_data = s;
- s1->nb_streams = 1;
- s1->streams[0] = st;
s->sample_rate = ap->sample_rate;
s->channels = ap->channels;
ret = audio_open(s, 0);
if (ret < 0) {
- free(st);
- free(s);
+ av_free(st);
return -EIO;
- } else {
- /* take real parameters */
- st->codec.codec_type = CODEC_TYPE_AUDIO;
- st->codec.codec_id = s->codec_id;
- st->codec.sample_rate = s->sample_rate;
- st->codec.channels = s->channels;
- return 0;
}
+
+ /* take real parameters */
+ st->codec.codec_type = CODEC_TYPE_AUDIO;
+ st->codec.codec_id = s->codec_id;
+ st->codec.sample_rate = s->sample_rate;
+ st->codec.channels = s->channels;
+
+ av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */
+ return 0;
}
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
AudioData *s = s1->priv_data;
- int ret;
-
+ int ret, bdelay;
+ int64_t cur_time;
+ struct audio_buf_info abufi;
+
if (av_new_packet(pkt, s->frame_size) < 0)
return -EIO;
for(;;) {
}
}
pkt->size = ret;
+
+ /* compute pts of the start of the packet */
+ cur_time = av_gettime();
+ bdelay = ret;
+ if (ioctl(s->fd, SNDCTL_DSP_GETISPACE, &abufi) == 0) {
+ bdelay += abufi.bytes;
+ }
+ /* substract time represented by the number of bytes in the audio fifo */
+ cur_time -= (bdelay * 1000000LL) / (s->sample_rate * s->channels);
+
+ /* convert to wanted units */
+ pkt->pts = cur_time & ((1LL << 48) - 1);
+
+ if (s->flip_left && s->channels == 2) {
+ int i;
+ short *p = (short *) pkt->data;
+
+ for (i = 0; i < ret; i += 4) {
+ *p = ~*p;
+ p += 2;
+ }
+ }
return 0;
}
AudioData *s = s1->priv_data;
audio_close(s);
- free(s);
return 0;
}
-AVFormat audio_device_format = {
+static AVInputFormat audio_in_format = {
+ "audio_device",
+ "audio grab and output",
+ sizeof(AudioData),
+ NULL,
+ audio_read_header,
+ audio_read_packet,
+ audio_read_close,
+ .flags = AVFMT_NOFILE,
+};
+
+static AVOutputFormat audio_out_format = {
"audio_device",
"audio grab and output",
"",
"",
+ sizeof(AudioData),
/* XXX: we make the assumption that the soundcard accepts this format */
/* XXX: find better solution with "preinit" method, needed also in
other formats */
audio_write_header,
audio_write_packet,
audio_write_trailer,
-
- audio_read_header,
- audio_read_packet,
- audio_read_close,
- NULL,
- AVFMT_NOFILE,
+ .flags = AVFMT_NOFILE,
};
+
+int audio_init(void)
+{
+ av_register_input_format(&audio_in_format);
+ av_register_output_format(&audio_out_format);
+ return 0;
+}