Browse Source

sndio support for playback and record

Signed-off-by: Anton Khirnov <anton@khirnov.net>
tags/n0.8
Brad Anton Khirnov 14 years ago
parent
commit
15d59d2cea
11 changed files with 403 additions and 2 deletions
  1. +1
    -0
      Changelog
  2. +6
    -0
      configure
  3. +17
    -0
      doc/indevs.texi
  4. +4
    -0
      doc/outdevs.texi
  5. +3
    -0
      libavdevice/Makefile
  6. +1
    -0
      libavdevice/alldevices.c
  7. +2
    -2
      libavdevice/avdevice.h
  8. +120
    -0
      libavdevice/sndio_common.c
  9. +46
    -0
      libavdevice/sndio_common.h
  10. +108
    -0
      libavdevice/sndio_dec.c
  11. +95
    -0
      libavdevice/sndio_enc.c

+ 1
- 0
Changelog 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
- 0
configure 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 &&


+ 17
- 0
doc/indevs.texi 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.


+ 4
- 0
doc/outdevs.texi 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

+ 3
- 0
libavdevice/Makefile 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

+ 1
- 0
libavdevice/alldevices.c 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);


+ 2
- 2
libavdevice/avdevice.h 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
- 0
libavdevice/sndio_common.c 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;
}

+ 46
- 0
libavdevice/sndio_common.h 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
- 0
libavdevice/sndio_dec.c 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
- 0
libavdevice/sndio_enc.c 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,
};

Loading…
Cancel
Save