1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

sndio support for playback and record

Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
Brad 2011-03-26 19:03:41 -04:00 committed by Anton Khirnov
parent 1500be13f2
commit 15d59d2cea
11 changed files with 403 additions and 2 deletions

View File

@ -79,6 +79,7 @@ version <next>:
- Bink version 'b' audio and video decoder
- Bitmap Brothers JV playback system
- Apple HTTP Live Streaming protocol handler
- sndio support for playback and record
version 0.6:

6
configure vendored
View File

@ -1094,6 +1094,7 @@ HAVE_LIST="
sdl
sdl_video_size
setmode
sndio_h
socklen_t
soundcard_h
poll_h
@ -1433,6 +1434,8 @@ jack_indev_deps="jack_jack_h"
libdc1394_indev_deps="libdc1394"
oss_indev_deps_any="soundcard_h sys_soundcard_h"
oss_outdev_deps_any="soundcard_h sys_soundcard_h"
sndio_indev_deps="sndio_h"
sndio_outdev_deps="sndio_h"
v4l_indev_deps="linux_videodev_h"
v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h"
vfwcap_indev_deps="capCreateCaptureWindow vfwcap_defines"
@ -2912,6 +2915,7 @@ check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_def
check_header dev/video/bktr/ioctl_bt848.h; } ||
check_header dev/ic/bt8xx.h
check_header sndio.h
check_header sys/soundcard.h
check_header soundcard.h
@ -2919,6 +2923,8 @@ enabled_any alsa_indev alsa_outdev && check_lib2 alsa/asoundlib.h snd_pcm_htimes
enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack
enabled_any sndio_indev sndio_outdev && check_lib2 sndio.h sio_open -lsndio
enabled x11grab &&
check_header X11/Xlib.h &&
check_header X11/extensions/XShm.h &&

View File

@ -129,6 +129,23 @@ ffmpeg -f oss -i /dev/dsp /tmp/oss.wav
For more information about OSS see:
@url{http://manuals.opensound.com/usersguide/dsp.html}
@section sndio
sndio input device.
To enable this input device during configuration you need libsndio
installed on your system.
The filename to provide to the input device is the device node
representing the sndio input device, and is usually set to
@file{/dev/audio0}.
For example to grab from @file{/dev/audio0} using @file{ffmpeg} use the
command:
@example
ffmpeg -f sndio -i /dev/audio0 /tmp/oss.wav
@end example
@section video4linux and video4linux2
Video4Linux and Video4Linux2 input video devices.

View File

@ -26,4 +26,8 @@ ALSA (Advanced Linux Sound Architecture) output device.
OSS (Open Sound System) output device.
@section sndio
sndio audio output device.
@c man end OUTPUT DEVICES

View File

@ -17,6 +17,8 @@ OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o
OBJS-$(CONFIG_OSS_INDEV) += oss_audio.o
OBJS-$(CONFIG_OSS_OUTDEV) += oss_audio.o
OBJS-$(CONFIG_SNDIO_INDEV) += sndio_common.o sndio_dec.o
OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_common.o sndio_enc.o
OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o
OBJS-$(CONFIG_V4L_INDEV) += v4l.o
OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o
@ -26,5 +28,6 @@ OBJS-$(CONFIG_X11_GRAB_DEVICE_INDEV) += x11grab.o
OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o
SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H) += alsa-audio.h
SKIPHEADERS-$(HAVE_SNDIO_H) += sndio_common.h
include $(SUBDIR)../subdir.mak

View File

@ -44,6 +44,7 @@ void avdevice_register_all(void)
REGISTER_INDEV (DV1394, dv1394);
REGISTER_INDEV (JACK, jack);
REGISTER_INOUTDEV (OSS, oss);
REGISTER_INOUTDEV (SNDIO, sndio);
REGISTER_INDEV (V4L2, v4l2);
REGISTER_INDEV (V4L, v4l);
REGISTER_INDEV (VFWCAP, vfwcap);

View File

@ -22,8 +22,8 @@
#include "libavutil/avutil.h"
#define LIBAVDEVICE_VERSION_MAJOR 52
#define LIBAVDEVICE_VERSION_MINOR 2
#define LIBAVDEVICE_VERSION_MICRO 3
#define LIBAVDEVICE_VERSION_MINOR 3
#define LIBAVDEVICE_VERSION_MICRO 0
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \

120
libavdevice/sndio_common.c Normal file
View File

@ -0,0 +1,120 @@
/*
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
* This file is part of Libav.
*
* Libav 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.1 of the License, or (at your option) any later version.
*
* Libav 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <sndio.h>
#include "libavformat/avformat.h"
#include "sndio_common.h"
static inline void movecb(void *addr, int delta)
{
SndioData *s = addr;
s->hwpos += delta * s->channels * s->bps;
}
av_cold int ff_sndio_open(AVFormatContext *s1, int is_output,
const char *audio_device)
{
SndioData *s = s1->priv_data;
struct sio_hdl *hdl;
struct sio_par par;
hdl = sio_open(audio_device, is_output ? SIO_PLAY : SIO_REC, 0);
if (!hdl) {
av_log(s1, AV_LOG_ERROR, "Could not open sndio device\n");
return AVERROR(EIO);
}
sio_initpar(&par);
par.bits = 16;
par.sig = 1;
par.le = SIO_LE_NATIVE;
if (is_output)
par.pchan = s->channels;
else
par.rchan = s->channels;
par.rate = s->sample_rate;
if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
av_log(s1, AV_LOG_ERROR, "Impossible to set sndio parameters, "
"channels: %d sample rate: %d\n", s->channels, s->sample_rate);
goto fail;
}
if (par.bits != 16 || par.sig != 1 || par.le != SIO_LE_NATIVE ||
(is_output && (par.pchan != s->channels)) ||
(!is_output && (par.rchan != s->channels)) ||
(par.rate != s->sample_rate)) {
av_log(s1, AV_LOG_ERROR, "Could not set appropriate sndio parameters, "
"channels: %d sample rate: %d\n", s->channels, s->sample_rate);
goto fail;
}
s->buffer_size = par.round * par.bps *
(is_output ? par.pchan : par.rchan);
if (is_output) {
s->buffer = av_malloc(s->buffer_size);
if (!s->buffer) {
av_log(s1, AV_LOG_ERROR, "Could not allocate buffer\n");
goto fail;
}
}
s->codec_id = par.le ? CODEC_ID_PCM_S16LE : CODEC_ID_PCM_S16BE;
s->channels = is_output ? par.pchan : par.rchan;
s->sample_rate = par.rate;
s->bps = par.bps;
sio_onmove(hdl, movecb, s);
if (!sio_start(hdl)) {
av_log(s1, AV_LOG_ERROR, "Could not start sndio\n");
goto fail;
}
s->hdl = hdl;
return 0;
fail:
av_freep(&s->buffer);
if (hdl)
sio_close(hdl);
return AVERROR(EIO);
}
int ff_sndio_close(SndioData *s)
{
av_freep(&s->buffer);
if (s->hdl)
sio_close(s->hdl);
return 0;
}

View File

@ -0,0 +1,46 @@
/*
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
* This file is part of Libav.
*
* Libav 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.1 of the License, or (at your option) any later version.
*
* Libav 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVDEVICE_SNDIO_COMMON_H
#define AVDEVICE_SNDIO_COMMON_H
#include <stdint.h>
#include <sndio.h>
#include "libavformat/avformat.h"
typedef struct {
struct sio_hdl *hdl;
enum CodecID codec_id;
int64_t hwpos;
int64_t softpos;
uint8_t *buffer;
int bps;
int buffer_size;
int buffer_offset;
int channels;
int sample_rate;
} SndioData;
int ff_sndio_open(AVFormatContext *s1, int is_output, const char *audio_device);
int ff_sndio_close(SndioData *s);
#endif /* AVDEVICE_SNDIO_COMMON_H */

108
libavdevice/sndio_dec.c Normal file
View File

@ -0,0 +1,108 @@
/*
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
* This file is part of Libav.
*
* Libav 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.1 of the License, or (at your option) any later version.
*
* Libav 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <sndio.h>
#include "libavformat/avformat.h"
#include "sndio_common.h"
static av_cold int audio_read_header(AVFormatContext *s1,
AVFormatParameters *ap)
{
SndioData *s = s1->priv_data;
AVStream *st;
int ret;
if (ap->sample_rate <= 0 || ap->channels <= 0)
return AVERROR(EINVAL);
st = av_new_stream(s1, 0);
if (!st)
return AVERROR(ENOMEM);
s->sample_rate = ap->sample_rate;
s->channels = ap->channels;
ret = ff_sndio_open(s1, 0, s1->filename);
if (ret < 0)
return ret;
/* take real parameters */
st->codec->codec_type = AVMEDIA_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(st, 64, 1, 1000000); /* 64 bits pts in us */
return 0;
}
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
SndioData *s = s1->priv_data;
int64_t bdelay, cur_time;
int ret;
if ((ret = av_new_packet(pkt, s->buffer_size)) < 0)
return ret;
ret = sio_read(s->hdl, pkt->data, pkt->size);
if (ret == 0 || sio_eof(s->hdl)) {
av_free_packet(pkt);
return AVERROR_EOF;
}
pkt->size = ret;
s->softpos += ret;
/* compute pts of the start of the packet */
cur_time = av_gettime();
bdelay = ret + s->hwpos - s->softpos;
/* convert to pts */
pkt->pts = cur_time - ((bdelay * 1000000) /
(s->bps * s->channels * s->sample_rate));
return 0;
}
static av_cold int audio_read_close(AVFormatContext *s1)
{
SndioData *s = s1->priv_data;
ff_sndio_close(s);
return 0;
}
AVInputFormat ff_sndio_demuxer = {
.name = "sndio",
.long_name = NULL_IF_CONFIG_SMALL("sndio audio capture"),
.priv_data_size = sizeof(SndioData),
.read_header = audio_read_header,
.read_packet = audio_read_packet,
.read_close = audio_read_close,
.flags = AVFMT_NOFILE,
};

95
libavdevice/sndio_enc.c Normal file
View File

@ -0,0 +1,95 @@
/*
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
* This file is part of Libav.
*
* Libav 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.1 of the License, or (at your option) any later version.
*
* Libav 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <sndio.h>
#include "libavformat/avformat.h"
#include "sndio_common.h"
static av_cold int audio_write_header(AVFormatContext *s1)
{
SndioData *s = s1->priv_data;
AVStream *st;
int ret;
st = s1->streams[0];
s->sample_rate = st->codec->sample_rate;
s->channels = st->codec->channels;
ret = ff_sndio_open(s1, 1, s1->filename);
return ret;
}
static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
{
SndioData *s = s1->priv_data;
uint8_t *buf= pkt->data;
int size = pkt->size;
int len, ret;
while (size > 0) {
len = s->buffer_size - s->buffer_offset;
if (len > size)
len = size;
memcpy(s->buffer + s->buffer_offset, buf, len);
buf += len;
size -= len;
s->buffer_offset += len;
if (s->buffer_offset >= s->buffer_size) {
ret = sio_write(s->hdl, s->buffer, s->buffer_size);
if (ret == 0 || sio_eof(s->hdl))
return AVERROR(EIO);
s->softpos += ret;
s->buffer_offset = 0;
}
}
return 0;
}
static int audio_write_trailer(AVFormatContext *s1)
{
SndioData *s = s1->priv_data;
sio_write(s->hdl, s->buffer, s->buffer_offset);
ff_sndio_close(s);
return 0;
}
AVOutputFormat ff_sndio_muxer = {
.name = "sndio",
.long_name = NULL_IF_CONFIG_SMALL("sndio audio playback"),
.priv_data_size = sizeof(SndioData),
/* XXX: we make the assumption that the soundcard accepts this format */
/* XXX: find better solution with "preinit" method, needed also in
other formats */
.audio_codec = AV_NE(CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE),
.video_codec = CODEC_ID_NONE,
.write_header = audio_write_header,
.write_packet = audio_write_packet,
.write_trailer = audio_write_trailer,
.flags = AVFMT_NOFILE,
};