From 8d26c193fb42d08602ac93ece039d4718d029adc Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Fri, 27 Mar 2015 12:40:23 +0100 Subject: avdevice: Apply a more consistent file naming scheme --- libavdevice/Makefile | 20 +-- libavdevice/alsa-audio-common.c | 362 ---------------------------------------- libavdevice/alsa-audio-dec.c | 178 -------------------- libavdevice/alsa-audio-enc.c | 117 ------------- libavdevice/alsa-audio.h | 96 ----------- libavdevice/alsa.c | 362 ++++++++++++++++++++++++++++++++++++++++ libavdevice/alsa.h | 96 +++++++++++ libavdevice/alsa_dec.c | 178 ++++++++++++++++++++ libavdevice/alsa_enc.c | 117 +++++++++++++ libavdevice/jack.c | 353 +++++++++++++++++++++++++++++++++++++++ libavdevice/jack_audio.c | 353 --------------------------------------- libavdevice/oss.c | 139 +++++++++++++++ libavdevice/oss.h | 45 +++++ libavdevice/oss_audio.c | 139 --------------- libavdevice/oss_audio.h | 45 ----- libavdevice/oss_audio_dec.c | 146 ---------------- libavdevice/oss_audio_enc.c | 108 ------------ libavdevice/oss_dec.c | 146 ++++++++++++++++ libavdevice/oss_enc.c | 108 ++++++++++++ libavdevice/sndio.c | 120 +++++++++++++ libavdevice/sndio.h | 48 ++++++ libavdevice/sndio_common.c | 120 ------------- libavdevice/sndio_common.h | 48 ------ libavdevice/sndio_dec.c | 2 +- libavdevice/sndio_enc.c | 2 +- 25 files changed, 1723 insertions(+), 1725 deletions(-) delete mode 100644 libavdevice/alsa-audio-common.c delete mode 100644 libavdevice/alsa-audio-dec.c delete mode 100644 libavdevice/alsa-audio-enc.c delete mode 100644 libavdevice/alsa-audio.h create mode 100644 libavdevice/alsa.c create mode 100644 libavdevice/alsa.h create mode 100644 libavdevice/alsa_dec.c create mode 100644 libavdevice/alsa_enc.c create mode 100644 libavdevice/jack.c delete mode 100644 libavdevice/jack_audio.c create mode 100644 libavdevice/oss.c create mode 100644 libavdevice/oss.h delete mode 100644 libavdevice/oss_audio.c delete mode 100644 libavdevice/oss_audio.h delete mode 100644 libavdevice/oss_audio_dec.c delete mode 100644 libavdevice/oss_audio_enc.c create mode 100644 libavdevice/oss_dec.c create mode 100644 libavdevice/oss_enc.c create mode 100644 libavdevice/sndio.c create mode 100644 libavdevice/sndio.h delete mode 100644 libavdevice/sndio_common.c delete mode 100644 libavdevice/sndio_common.h (limited to 'libavdevice') diff --git a/libavdevice/Makefile b/libavdevice/Makefile index 2a2183288f..dfd56be842 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -7,19 +7,17 @@ OBJS = alldevices.o \ avdevice.o \ # input/output devices -OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \ - alsa-audio-dec.o -OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \ - alsa-audio-enc.o +OBJS-$(CONFIG_ALSA_INDEV) += alsa_dec.o alsa.o +OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o OBJS-$(CONFIG_FBDEV_INDEV) += fbdev.o -OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o timefilter.o -OBJS-$(CONFIG_OSS_INDEV) += oss_audio.o oss_audio_dec.o -OBJS-$(CONFIG_OSS_OUTDEV) += oss_audio.o oss_audio_enc.o +OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o +OBJS-$(CONFIG_OSS_INDEV) += oss_dec.o oss.o +OBJS-$(CONFIG_OSS_OUTDEV) += oss_enc.o oss.o OBJS-$(CONFIG_PULSE_INDEV) += pulse.o -OBJS-$(CONFIG_SNDIO_INDEV) += sndio_common.o sndio_dec.o -OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_common.o sndio_enc.o +OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o +OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o OBJS-$(CONFIG_X11GRAB_INDEV) += x11grab.o @@ -31,7 +29,7 @@ OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o -SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H) += alsa-audio.h -SKIPHEADERS-$(HAVE_SNDIO_H) += sndio_common.h +SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H) += alsa.h +SKIPHEADERS-$(HAVE_SNDIO_H) += sndio.h TESTPROGS = timefilter diff --git a/libavdevice/alsa-audio-common.c b/libavdevice/alsa-audio-common.c deleted file mode 100644 index 21f1594241..0000000000 --- a/libavdevice/alsa-audio-common.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * ALSA input and output - * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) - * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) - * - * 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 - */ - -/** - * @file - * ALSA input and output: common code - * @author Luca Abeni ( lucabe72 email it ) - * @author Benoit Fouet ( benoit fouet free fr ) - * @author Nicolas George ( nicolas george normalesup org ) - */ - -#include -#include "libavformat/avformat.h" -#include "libavutil/avassert.h" -#include "libavutil/channel_layout.h" - -#include "alsa-audio.h" - -static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id) -{ - switch(codec_id) { - case AV_CODEC_ID_PCM_F64LE: return SND_PCM_FORMAT_FLOAT64_LE; - case AV_CODEC_ID_PCM_F64BE: return SND_PCM_FORMAT_FLOAT64_BE; - case AV_CODEC_ID_PCM_F32LE: return SND_PCM_FORMAT_FLOAT_LE; - case AV_CODEC_ID_PCM_F32BE: return SND_PCM_FORMAT_FLOAT_BE; - case AV_CODEC_ID_PCM_S32LE: return SND_PCM_FORMAT_S32_LE; - case AV_CODEC_ID_PCM_S32BE: return SND_PCM_FORMAT_S32_BE; - case AV_CODEC_ID_PCM_U32LE: return SND_PCM_FORMAT_U32_LE; - case AV_CODEC_ID_PCM_U32BE: return SND_PCM_FORMAT_U32_BE; - case AV_CODEC_ID_PCM_S24LE: return SND_PCM_FORMAT_S24_3LE; - case AV_CODEC_ID_PCM_S24BE: return SND_PCM_FORMAT_S24_3BE; - case AV_CODEC_ID_PCM_U24LE: return SND_PCM_FORMAT_U24_3LE; - case AV_CODEC_ID_PCM_U24BE: return SND_PCM_FORMAT_U24_3BE; - case AV_CODEC_ID_PCM_S16LE: return SND_PCM_FORMAT_S16_LE; - case AV_CODEC_ID_PCM_S16BE: return SND_PCM_FORMAT_S16_BE; - case AV_CODEC_ID_PCM_U16LE: return SND_PCM_FORMAT_U16_LE; - case AV_CODEC_ID_PCM_U16BE: return SND_PCM_FORMAT_U16_BE; - case AV_CODEC_ID_PCM_S8: return SND_PCM_FORMAT_S8; - case AV_CODEC_ID_PCM_U8: return SND_PCM_FORMAT_U8; - case AV_CODEC_ID_PCM_MULAW: return SND_PCM_FORMAT_MU_LAW; - case AV_CODEC_ID_PCM_ALAW: return SND_PCM_FORMAT_A_LAW; - default: return SND_PCM_FORMAT_UNKNOWN; - } -} - -#define REORDER_OUT_50(NAME, TYPE) \ -static void alsa_reorder_ ## NAME ## _out_50(const void *in_v, void *out_v, int n) \ -{ \ - const TYPE *in = in_v; \ - TYPE *out = out_v; \ -\ - while (n-- > 0) { \ - out[0] = in[0]; \ - out[1] = in[1]; \ - out[2] = in[3]; \ - out[3] = in[4]; \ - out[4] = in[2]; \ - in += 5; \ - out += 5; \ - } \ -} - -#define REORDER_OUT_51(NAME, TYPE) \ -static void alsa_reorder_ ## NAME ## _out_51(const void *in_v, void *out_v, int n) \ -{ \ - const TYPE *in = in_v; \ - TYPE *out = out_v; \ -\ - while (n-- > 0) { \ - out[0] = in[0]; \ - out[1] = in[1]; \ - out[2] = in[4]; \ - out[3] = in[5]; \ - out[4] = in[2]; \ - out[5] = in[3]; \ - in += 6; \ - out += 6; \ - } \ -} - -#define REORDER_OUT_71(NAME, TYPE) \ -static void alsa_reorder_ ## NAME ## _out_71(const void *in_v, void *out_v, int n) \ -{ \ - const TYPE *in = in_v; \ - TYPE *out = out_v; \ -\ - while (n-- > 0) { \ - out[0] = in[0]; \ - out[1] = in[1]; \ - out[2] = in[4]; \ - out[3] = in[5]; \ - out[4] = in[2]; \ - out[5] = in[3]; \ - out[6] = in[6]; \ - out[7] = in[7]; \ - in += 8; \ - out += 8; \ - } \ -} - -REORDER_OUT_50(int8, int8_t) -REORDER_OUT_51(int8, int8_t) -REORDER_OUT_71(int8, int8_t) -REORDER_OUT_50(int16, int16_t) -REORDER_OUT_51(int16, int16_t) -REORDER_OUT_71(int16, int16_t) -REORDER_OUT_50(int32, int32_t) -REORDER_OUT_51(int32, int32_t) -REORDER_OUT_71(int32, int32_t) -REORDER_OUT_50(f32, float) -REORDER_OUT_51(f32, float) -REORDER_OUT_71(f32, float) - -#define FORMAT_I8 0 -#define FORMAT_I16 1 -#define FORMAT_I32 2 -#define FORMAT_F32 3 - -#define PICK_REORDER(layout)\ -switch(format) {\ - case FORMAT_I8: s->reorder_func = alsa_reorder_int8_out_ ##layout; break;\ - case FORMAT_I16: s->reorder_func = alsa_reorder_int16_out_ ##layout; break;\ - case FORMAT_I32: s->reorder_func = alsa_reorder_int32_out_ ##layout; break;\ - case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\ -} - -static av_cold int find_reorder_func(AlsaData *s, int codec_id, uint64_t layout, int out) -{ - int format; - - /* reordering input is not currently supported */ - if (!out) - return AVERROR(ENOSYS); - - /* reordering is not needed for QUAD or 2_2 layout */ - if (layout == AV_CH_LAYOUT_QUAD || layout == AV_CH_LAYOUT_2_2) - return 0; - - switch (codec_id) { - case AV_CODEC_ID_PCM_S8: - case AV_CODEC_ID_PCM_U8: - case AV_CODEC_ID_PCM_ALAW: - case AV_CODEC_ID_PCM_MULAW: format = FORMAT_I8; break; - case AV_CODEC_ID_PCM_S16LE: - case AV_CODEC_ID_PCM_S16BE: - case AV_CODEC_ID_PCM_U16LE: - case AV_CODEC_ID_PCM_U16BE: format = FORMAT_I16; break; - case AV_CODEC_ID_PCM_S32LE: - case AV_CODEC_ID_PCM_S32BE: - case AV_CODEC_ID_PCM_U32LE: - case AV_CODEC_ID_PCM_U32BE: format = FORMAT_I32; break; - case AV_CODEC_ID_PCM_F32LE: - case AV_CODEC_ID_PCM_F32BE: format = FORMAT_F32; break; - default: return AVERROR(ENOSYS); - } - - if (layout == AV_CH_LAYOUT_5POINT0_BACK || layout == AV_CH_LAYOUT_5POINT0) - PICK_REORDER(50) - else if (layout == AV_CH_LAYOUT_5POINT1_BACK || layout == AV_CH_LAYOUT_5POINT1) - PICK_REORDER(51) - else if (layout == AV_CH_LAYOUT_7POINT1) - PICK_REORDER(71) - - return s->reorder_func ? 0 : AVERROR(ENOSYS); -} - -av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, - unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id) -{ - AlsaData *s = ctx->priv_data; - const char *audio_device; - int res, flags = 0; - snd_pcm_format_t format; - snd_pcm_t *h; - snd_pcm_hw_params_t *hw_params; - snd_pcm_uframes_t buffer_size, period_size; - uint64_t layout = ctx->streams[0]->codec->channel_layout; - - if (ctx->filename[0] == 0) audio_device = "default"; - else audio_device = ctx->filename; - - if (*codec_id == AV_CODEC_ID_NONE) - *codec_id = DEFAULT_CODEC_ID; - format = codec_id_to_pcm_format(*codec_id); - if (format == SND_PCM_FORMAT_UNKNOWN) { - av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); - return AVERROR(ENOSYS); - } - s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; - - if (ctx->flags & AVFMT_FLAG_NONBLOCK) { - flags = SND_PCM_NONBLOCK; - } - res = snd_pcm_open(&h, audio_device, mode, flags); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n", - audio_device, snd_strerror(res)); - return AVERROR(EIO); - } - - res = snd_pcm_hw_params_malloc(&hw_params); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n", - snd_strerror(res)); - goto fail1; - } - - res = snd_pcm_hw_params_any(h, hw_params); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n", - snd_strerror(res)); - goto fail; - } - - res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n", - snd_strerror(res)); - goto fail; - } - - res = snd_pcm_hw_params_set_format(h, hw_params, format); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n", - *codec_id, format, snd_strerror(res)); - goto fail; - } - - res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n", - snd_strerror(res)); - goto fail; - } - - res = snd_pcm_hw_params_set_channels(h, hw_params, channels); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", - channels, snd_strerror(res)); - goto fail; - } - - snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); - buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX); - /* TODO: maybe use ctx->max_picture_buffer somehow */ - res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n", - snd_strerror(res)); - goto fail; - } - - snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); - if (!period_size) - period_size = buffer_size / 4; - res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n", - snd_strerror(res)); - goto fail; - } - s->period_size = period_size; - - res = snd_pcm_hw_params(h, hw_params); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n", - snd_strerror(res)); - goto fail; - } - - snd_pcm_hw_params_free(hw_params); - - if (channels > 2 && layout) { - if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) { - char name[128]; - av_get_channel_layout_string(name, sizeof(name), channels, layout); - av_log(ctx, AV_LOG_WARNING, "ALSA channel layout unknown or unimplemented for %s %s.\n", - name, mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture"); - } - if (s->reorder_func) { - s->reorder_buf_size = buffer_size; - s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size); - if (!s->reorder_buf) - goto fail1; - } - } - - s->h = h; - return 0; - -fail: - snd_pcm_hw_params_free(hw_params); -fail1: - snd_pcm_close(h); - return AVERROR(EIO); -} - -av_cold int ff_alsa_close(AVFormatContext *s1) -{ - AlsaData *s = s1->priv_data; - - av_freep(&s->reorder_buf); - snd_pcm_close(s->h); - return 0; -} - -int ff_alsa_xrun_recover(AVFormatContext *s1, int err) -{ - AlsaData *s = s1->priv_data; - snd_pcm_t *handle = s->h; - - av_log(s1, AV_LOG_WARNING, "ALSA buffer xrun.\n"); - if (err == -EPIPE) { - err = snd_pcm_prepare(handle); - if (err < 0) { - av_log(s1, AV_LOG_ERROR, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err)); - - return AVERROR(EIO); - } - } else if (err == -ESTRPIPE) { - av_log(s1, AV_LOG_ERROR, "-ESTRPIPE... Unsupported!\n"); - - return -1; - } - return err; -} - -int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size) -{ - int size = s->reorder_buf_size; - void *r; - - av_assert0(size != 0); - while (size < min_size) - size *= 2; - r = av_realloc(s->reorder_buf, size * s->frame_size); - if (!r) - return AVERROR(ENOMEM); - s->reorder_buf = r; - s->reorder_buf_size = size; - return 0; -} diff --git a/libavdevice/alsa-audio-dec.c b/libavdevice/alsa-audio-dec.c deleted file mode 100644 index a6a814b80f..0000000000 --- a/libavdevice/alsa-audio-dec.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * ALSA input and output - * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) - * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) - * - * 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 - */ - -/** - * @file - * ALSA input and output: input - * @author Luca Abeni ( lucabe72 email it ) - * @author Benoit Fouet ( benoit fouet free fr ) - * @author Nicolas George ( nicolas george normalesup org ) - * - * This avdevice decoder allows to capture audio from an ALSA (Advanced - * Linux Sound Architecture) device. - * - * The filename parameter is the name of an ALSA PCM device capable of - * capture, for example "default" or "plughw:1"; see the ALSA documentation - * for naming conventions. The empty string is equivalent to "default". - * - * The capture period is set to the lower value available for the device, - * which gives a low latency suitable for real-time capture. - * - * The PTS are an Unix time in microsecond. - * - * Due to a bug in the ALSA library - * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4308), this - * decoder does not work with certain ALSA plugins, especially the dsnoop - * plugin. - */ - -#include - -#include "libavutil/internal.h" -#include "libavutil/opt.h" - -#include "libavformat/avformat.h" -#include "libavformat/internal.h" - -#include "alsa-audio.h" - -static av_cold int audio_read_header(AVFormatContext *s1) -{ - AlsaData *s = s1->priv_data; - AVStream *st; - int ret; - enum AVCodecID codec_id; - snd_pcm_sw_params_t *sw_params; - - st = avformat_new_stream(s1, NULL); - if (!st) { - av_log(s1, AV_LOG_ERROR, "Cannot add stream\n"); - - return AVERROR(ENOMEM); - } - codec_id = s1->audio_codec_id; - - ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels, - &codec_id); - if (ret < 0) { - return AVERROR(EIO); - } - - if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW) - av_log(s1, AV_LOG_WARNING, - "capture with some ALSA plugins, especially dsnoop, " - "may hang.\n"); - - ret = snd_pcm_sw_params_malloc(&sw_params); - if (ret < 0) { - av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n", - snd_strerror(ret)); - goto fail; - } - - snd_pcm_sw_params_current(s->h, sw_params); - snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE); - - ret = snd_pcm_sw_params(s->h, sw_params); - snd_pcm_sw_params_free(sw_params); - if (ret < 0) { - av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n", - snd_strerror(ret)); - goto fail; - } - - /* take real parameters */ - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = codec_id; - st->codec->sample_rate = s->sample_rate; - st->codec->channels = s->channels; - avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - - return 0; - -fail: - snd_pcm_close(s->h); - return AVERROR(EIO); -} - -static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - AlsaData *s = s1->priv_data; - AVStream *st = s1->streams[0]; - int res; - snd_htimestamp_t timestamp; - snd_pcm_uframes_t ts_delay; - - if (av_new_packet(pkt, s->period_size) < 0) { - return AVERROR(EIO); - } - - while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) { - if (res == -EAGAIN) { - av_free_packet(pkt); - - return AVERROR(EAGAIN); - } - if (ff_alsa_xrun_recover(s1, res) < 0) { - av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n", - snd_strerror(res)); - av_free_packet(pkt); - - return AVERROR(EIO); - } - } - - snd_pcm_htimestamp(s->h, &ts_delay, ×tamp); - ts_delay += res; - pkt->pts = timestamp.tv_sec * 1000000LL - + (timestamp.tv_nsec * st->codec->sample_rate - - (int64_t)ts_delay * 1000000000LL + st->codec->sample_rate * 500LL) - / (st->codec->sample_rate * 1000LL); - - pkt->size = res * s->frame_size; - - return 0; -} - -static const AVOption options[] = { - { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { NULL }, -}; - -static const AVClass alsa_demuxer_class = { - .class_name = "ALSA demuxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVInputFormat ff_alsa_demuxer = { - .name = "alsa", - .long_name = NULL_IF_CONFIG_SMALL("ALSA audio input"), - .priv_data_size = sizeof(AlsaData), - .read_header = audio_read_header, - .read_packet = audio_read_packet, - .read_close = ff_alsa_close, - .flags = AVFMT_NOFILE, - .priv_class = &alsa_demuxer_class, -}; diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c deleted file mode 100644 index db4f5e426f..0000000000 --- a/libavdevice/alsa-audio-enc.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ALSA input and output - * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) - * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) - * - * 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 - */ - -/** - * @file - * ALSA input and output: output - * @author Luca Abeni ( lucabe72 email it ) - * @author Benoit Fouet ( benoit fouet free fr ) - * - * This avdevice encoder allows to play audio to an ALSA (Advanced Linux - * Sound Architecture) device. - * - * The filename parameter is the name of an ALSA PCM device capable of - * capture, for example "default" or "plughw:1"; see the ALSA documentation - * for naming conventions. The empty string is equivalent to "default". - * - * The playback period is set to the lower value available for the device, - * which gives a low latency suitable for real-time playback. - */ - -#include - -#include "libavutil/internal.h" - -#include "libavformat/avformat.h" - -#include "alsa-audio.h" - -static av_cold int audio_write_header(AVFormatContext *s1) -{ - AlsaData *s = s1->priv_data; - AVStream *st; - unsigned int sample_rate; - enum AVCodecID codec_id; - int res; - - st = s1->streams[0]; - sample_rate = st->codec->sample_rate; - codec_id = st->codec->codec_id; - res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, - st->codec->channels, &codec_id); - if (sample_rate != st->codec->sample_rate) { - av_log(s1, AV_LOG_ERROR, - "sample rate %d not available, nearest is %d\n", - st->codec->sample_rate, sample_rate); - goto fail; - } - - return res; - -fail: - snd_pcm_close(s->h); - return AVERROR(EIO); -} - -static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) -{ - AlsaData *s = s1->priv_data; - int res; - int size = pkt->size; - uint8_t *buf = pkt->data; - - size /= s->frame_size; - if (s->reorder_func) { - if (size > s->reorder_buf_size) - if (ff_alsa_extend_reorder_buf(s, size)) - return AVERROR(ENOMEM); - s->reorder_func(buf, s->reorder_buf, size); - buf = s->reorder_buf; - } - while ((res = snd_pcm_writei(s->h, buf, size)) < 0) { - if (res == -EAGAIN) { - - return AVERROR(EAGAIN); - } - - if (ff_alsa_xrun_recover(s1, res) < 0) { - av_log(s1, AV_LOG_ERROR, "ALSA write error: %s\n", - snd_strerror(res)); - - return AVERROR(EIO); - } - } - - return 0; -} - -AVOutputFormat ff_alsa_muxer = { - .name = "alsa", - .long_name = NULL_IF_CONFIG_SMALL("ALSA audio output"), - .priv_data_size = sizeof(AlsaData), - .audio_codec = DEFAULT_CODEC_ID, - .video_codec = AV_CODEC_ID_NONE, - .write_header = audio_write_header, - .write_packet = audio_write_packet, - .write_trailer = ff_alsa_close, - .flags = AVFMT_NOFILE, -}; diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h deleted file mode 100644 index 26eaee6acf..0000000000 --- a/libavdevice/alsa-audio.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ALSA input and output - * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) - * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) - * - * 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 - */ - -/** - * @file - * ALSA input and output: definitions and structures - * @author Luca Abeni ( lucabe72 email it ) - * @author Benoit Fouet ( benoit fouet free fr ) - */ - -#ifndef AVDEVICE_ALSA_AUDIO_H -#define AVDEVICE_ALSA_AUDIO_H - -#include -#include "config.h" -#include "libavformat/avformat.h" -#include "libavutil/log.h" - -/* XXX: we make the assumption that the soundcard accepts this format */ -/* XXX: find better solution with "preinit" method, needed also in - other formats */ -#define DEFAULT_CODEC_ID AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE) - -#define ALSA_BUFFER_SIZE_MAX 32768 - -typedef struct AlsaData { - AVClass *class; - snd_pcm_t *h; - int frame_size; ///< preferred size for reads and writes - int period_size; ///< bytes per sample * channels - int sample_rate; ///< sample rate set by user - int channels; ///< number of channels set by user - void (*reorder_func)(const void *, void *, int); - void *reorder_buf; - int reorder_buf_size; ///< in frames -} AlsaData; - -/** - * Open an ALSA PCM. - * - * @param s media file handle - * @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK - * @param sample_rate in: requested sample rate; - * out: actually selected sample rate - * @param channels number of channels - * @param codec_id in: requested AVCodecID or AV_CODEC_ID_NONE; - * out: actually selected AVCodecID, changed only if - * AV_CODEC_ID_NONE was requested - * - * @return 0 if OK, AVERROR_xxx on error - */ -int ff_alsa_open(AVFormatContext *s, snd_pcm_stream_t mode, - unsigned int *sample_rate, - int channels, enum AVCodecID *codec_id); - -/** - * Close the ALSA PCM. - * - * @param s1 media file handle - * - * @return 0 - */ -int ff_alsa_close(AVFormatContext *s1); - -/** - * Try to recover from ALSA buffer underrun. - * - * @param s1 media file handle - * @param err error code reported by the previous ALSA call - * - * @return 0 if OK, AVERROR_xxx on error - */ -int ff_alsa_xrun_recover(AVFormatContext *s1, int err); - -int ff_alsa_extend_reorder_buf(AlsaData *s, int size); - -#endif /* AVDEVICE_ALSA_AUDIO_H */ diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c new file mode 100644 index 0000000000..6d68267602 --- /dev/null +++ b/libavdevice/alsa.c @@ -0,0 +1,362 @@ +/* + * ALSA input and output + * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) + * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) + * + * 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 + */ + +/** + * @file + * ALSA input and output: common code + * @author Luca Abeni ( lucabe72 email it ) + * @author Benoit Fouet ( benoit fouet free fr ) + * @author Nicolas George ( nicolas george normalesup org ) + */ + +#include +#include "libavformat/avformat.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" + +#include "alsa.h" + +static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id) +{ + switch(codec_id) { + case AV_CODEC_ID_PCM_F64LE: return SND_PCM_FORMAT_FLOAT64_LE; + case AV_CODEC_ID_PCM_F64BE: return SND_PCM_FORMAT_FLOAT64_BE; + case AV_CODEC_ID_PCM_F32LE: return SND_PCM_FORMAT_FLOAT_LE; + case AV_CODEC_ID_PCM_F32BE: return SND_PCM_FORMAT_FLOAT_BE; + case AV_CODEC_ID_PCM_S32LE: return SND_PCM_FORMAT_S32_LE; + case AV_CODEC_ID_PCM_S32BE: return SND_PCM_FORMAT_S32_BE; + case AV_CODEC_ID_PCM_U32LE: return SND_PCM_FORMAT_U32_LE; + case AV_CODEC_ID_PCM_U32BE: return SND_PCM_FORMAT_U32_BE; + case AV_CODEC_ID_PCM_S24LE: return SND_PCM_FORMAT_S24_3LE; + case AV_CODEC_ID_PCM_S24BE: return SND_PCM_FORMAT_S24_3BE; + case AV_CODEC_ID_PCM_U24LE: return SND_PCM_FORMAT_U24_3LE; + case AV_CODEC_ID_PCM_U24BE: return SND_PCM_FORMAT_U24_3BE; + case AV_CODEC_ID_PCM_S16LE: return SND_PCM_FORMAT_S16_LE; + case AV_CODEC_ID_PCM_S16BE: return SND_PCM_FORMAT_S16_BE; + case AV_CODEC_ID_PCM_U16LE: return SND_PCM_FORMAT_U16_LE; + case AV_CODEC_ID_PCM_U16BE: return SND_PCM_FORMAT_U16_BE; + case AV_CODEC_ID_PCM_S8: return SND_PCM_FORMAT_S8; + case AV_CODEC_ID_PCM_U8: return SND_PCM_FORMAT_U8; + case AV_CODEC_ID_PCM_MULAW: return SND_PCM_FORMAT_MU_LAW; + case AV_CODEC_ID_PCM_ALAW: return SND_PCM_FORMAT_A_LAW; + default: return SND_PCM_FORMAT_UNKNOWN; + } +} + +#define REORDER_OUT_50(NAME, TYPE) \ +static void alsa_reorder_ ## NAME ## _out_50(const void *in_v, void *out_v, int n) \ +{ \ + const TYPE *in = in_v; \ + TYPE *out = out_v; \ +\ + while (n-- > 0) { \ + out[0] = in[0]; \ + out[1] = in[1]; \ + out[2] = in[3]; \ + out[3] = in[4]; \ + out[4] = in[2]; \ + in += 5; \ + out += 5; \ + } \ +} + +#define REORDER_OUT_51(NAME, TYPE) \ +static void alsa_reorder_ ## NAME ## _out_51(const void *in_v, void *out_v, int n) \ +{ \ + const TYPE *in = in_v; \ + TYPE *out = out_v; \ +\ + while (n-- > 0) { \ + out[0] = in[0]; \ + out[1] = in[1]; \ + out[2] = in[4]; \ + out[3] = in[5]; \ + out[4] = in[2]; \ + out[5] = in[3]; \ + in += 6; \ + out += 6; \ + } \ +} + +#define REORDER_OUT_71(NAME, TYPE) \ +static void alsa_reorder_ ## NAME ## _out_71(const void *in_v, void *out_v, int n) \ +{ \ + const TYPE *in = in_v; \ + TYPE *out = out_v; \ +\ + while (n-- > 0) { \ + out[0] = in[0]; \ + out[1] = in[1]; \ + out[2] = in[4]; \ + out[3] = in[5]; \ + out[4] = in[2]; \ + out[5] = in[3]; \ + out[6] = in[6]; \ + out[7] = in[7]; \ + in += 8; \ + out += 8; \ + } \ +} + +REORDER_OUT_50(int8, int8_t) +REORDER_OUT_51(int8, int8_t) +REORDER_OUT_71(int8, int8_t) +REORDER_OUT_50(int16, int16_t) +REORDER_OUT_51(int16, int16_t) +REORDER_OUT_71(int16, int16_t) +REORDER_OUT_50(int32, int32_t) +REORDER_OUT_51(int32, int32_t) +REORDER_OUT_71(int32, int32_t) +REORDER_OUT_50(f32, float) +REORDER_OUT_51(f32, float) +REORDER_OUT_71(f32, float) + +#define FORMAT_I8 0 +#define FORMAT_I16 1 +#define FORMAT_I32 2 +#define FORMAT_F32 3 + +#define PICK_REORDER(layout)\ +switch(format) {\ + case FORMAT_I8: s->reorder_func = alsa_reorder_int8_out_ ##layout; break;\ + case FORMAT_I16: s->reorder_func = alsa_reorder_int16_out_ ##layout; break;\ + case FORMAT_I32: s->reorder_func = alsa_reorder_int32_out_ ##layout; break;\ + case FORMAT_F32: s->reorder_func = alsa_reorder_f32_out_ ##layout; break;\ +} + +static av_cold int find_reorder_func(AlsaData *s, int codec_id, uint64_t layout, int out) +{ + int format; + + /* reordering input is not currently supported */ + if (!out) + return AVERROR(ENOSYS); + + /* reordering is not needed for QUAD or 2_2 layout */ + if (layout == AV_CH_LAYOUT_QUAD || layout == AV_CH_LAYOUT_2_2) + return 0; + + switch (codec_id) { + case AV_CODEC_ID_PCM_S8: + case AV_CODEC_ID_PCM_U8: + case AV_CODEC_ID_PCM_ALAW: + case AV_CODEC_ID_PCM_MULAW: format = FORMAT_I8; break; + case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S16BE: + case AV_CODEC_ID_PCM_U16LE: + case AV_CODEC_ID_PCM_U16BE: format = FORMAT_I16; break; + case AV_CODEC_ID_PCM_S32LE: + case AV_CODEC_ID_PCM_S32BE: + case AV_CODEC_ID_PCM_U32LE: + case AV_CODEC_ID_PCM_U32BE: format = FORMAT_I32; break; + case AV_CODEC_ID_PCM_F32LE: + case AV_CODEC_ID_PCM_F32BE: format = FORMAT_F32; break; + default: return AVERROR(ENOSYS); + } + + if (layout == AV_CH_LAYOUT_5POINT0_BACK || layout == AV_CH_LAYOUT_5POINT0) + PICK_REORDER(50) + else if (layout == AV_CH_LAYOUT_5POINT1_BACK || layout == AV_CH_LAYOUT_5POINT1) + PICK_REORDER(51) + else if (layout == AV_CH_LAYOUT_7POINT1) + PICK_REORDER(71) + + return s->reorder_func ? 0 : AVERROR(ENOSYS); +} + +av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, + unsigned int *sample_rate, + int channels, enum AVCodecID *codec_id) +{ + AlsaData *s = ctx->priv_data; + const char *audio_device; + int res, flags = 0; + snd_pcm_format_t format; + snd_pcm_t *h; + snd_pcm_hw_params_t *hw_params; + snd_pcm_uframes_t buffer_size, period_size; + uint64_t layout = ctx->streams[0]->codec->channel_layout; + + if (ctx->filename[0] == 0) audio_device = "default"; + else audio_device = ctx->filename; + + if (*codec_id == AV_CODEC_ID_NONE) + *codec_id = DEFAULT_CODEC_ID; + format = codec_id_to_pcm_format(*codec_id); + if (format == SND_PCM_FORMAT_UNKNOWN) { + av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); + return AVERROR(ENOSYS); + } + s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; + + if (ctx->flags & AVFMT_FLAG_NONBLOCK) { + flags = SND_PCM_NONBLOCK; + } + res = snd_pcm_open(&h, audio_device, mode, flags); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n", + audio_device, snd_strerror(res)); + return AVERROR(EIO); + } + + res = snd_pcm_hw_params_malloc(&hw_params); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror(res)); + goto fail1; + } + + res = snd_pcm_hw_params_any(h, hw_params); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror(res)); + goto fail; + } + + res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n", + snd_strerror(res)); + goto fail; + } + + res = snd_pcm_hw_params_set_format(h, hw_params, format); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n", + *codec_id, format, snd_strerror(res)); + goto fail; + } + + res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n", + snd_strerror(res)); + goto fail; + } + + res = snd_pcm_hw_params_set_channels(h, hw_params, channels); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", + channels, snd_strerror(res)); + goto fail; + } + + snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); + buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX); + /* TODO: maybe use ctx->max_picture_buffer somehow */ + res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n", + snd_strerror(res)); + goto fail; + } + + snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); + if (!period_size) + period_size = buffer_size / 4; + res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n", + snd_strerror(res)); + goto fail; + } + s->period_size = period_size; + + res = snd_pcm_hw_params(h, hw_params); + if (res < 0) { + av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n", + snd_strerror(res)); + goto fail; + } + + snd_pcm_hw_params_free(hw_params); + + if (channels > 2 && layout) { + if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) { + char name[128]; + av_get_channel_layout_string(name, sizeof(name), channels, layout); + av_log(ctx, AV_LOG_WARNING, "ALSA channel layout unknown or unimplemented for %s %s.\n", + name, mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + } + if (s->reorder_func) { + s->reorder_buf_size = buffer_size; + s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size); + if (!s->reorder_buf) + goto fail1; + } + } + + s->h = h; + return 0; + +fail: + snd_pcm_hw_params_free(hw_params); +fail1: + snd_pcm_close(h); + return AVERROR(EIO); +} + +av_cold int ff_alsa_close(AVFormatContext *s1) +{ + AlsaData *s = s1->priv_data; + + av_freep(&s->reorder_buf); + snd_pcm_close(s->h); + return 0; +} + +int ff_alsa_xrun_recover(AVFormatContext *s1, int err) +{ + AlsaData *s = s1->priv_data; + snd_pcm_t *handle = s->h; + + av_log(s1, AV_LOG_WARNING, "ALSA buffer xrun.\n"); + if (err == -EPIPE) { + err = snd_pcm_prepare(handle); + if (err < 0) { + av_log(s1, AV_LOG_ERROR, "cannot recover from underrun (snd_pcm_prepare failed: %s)\n", snd_strerror(err)); + + return AVERROR(EIO); + } + } else if (err == -ESTRPIPE) { + av_log(s1, AV_LOG_ERROR, "-ESTRPIPE... Unsupported!\n"); + + return -1; + } + return err; +} + +int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size) +{ + int size = s->reorder_buf_size; + void *r; + + av_assert0(size != 0); + while (size < min_size) + size *= 2; + r = av_realloc(s->reorder_buf, size * s->frame_size); + if (!r) + return AVERROR(ENOMEM); + s->reorder_buf = r; + s->reorder_buf_size = size; + return 0; +} diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h new file mode 100644 index 0000000000..590b354053 --- /dev/null +++ b/libavdevice/alsa.h @@ -0,0 +1,96 @@ +/* + * ALSA input and output + * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) + * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) + * + * 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 + */ + +/** + * @file + * ALSA input and output: definitions and structures + * @author Luca Abeni ( lucabe72 email it ) + * @author Benoit Fouet ( benoit fouet free fr ) + */ + +#ifndef AVDEVICE_ALSA_H +#define AVDEVICE_ALSA_H + +#include +#include "config.h" +#include "libavformat/avformat.h" +#include "libavutil/log.h" + +/* XXX: we make the assumption that the soundcard accepts this format */ +/* XXX: find better solution with "preinit" method, needed also in + other formats */ +#define DEFAULT_CODEC_ID AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE) + +#define ALSA_BUFFER_SIZE_MAX 32768 + +typedef struct AlsaData { + AVClass *class; + snd_pcm_t *h; + int frame_size; ///< preferred size for reads and writes + int period_size; ///< bytes per sample * channels + int sample_rate; ///< sample rate set by user + int channels; ///< number of channels set by user + void (*reorder_func)(const void *, void *, int); + void *reorder_buf; + int reorder_buf_size; ///< in frames +} AlsaData; + +/** + * Open an ALSA PCM. + * + * @param s media file handle + * @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK + * @param sample_rate in: requested sample rate; + * out: actually selected sample rate + * @param channels number of channels + * @param codec_id in: requested AVCodecID or AV_CODEC_ID_NONE; + * out: actually selected AVCodecID, changed only if + * AV_CODEC_ID_NONE was requested + * + * @return 0 if OK, AVERROR_xxx on error + */ +int ff_alsa_open(AVFormatContext *s, snd_pcm_stream_t mode, + unsigned int *sample_rate, + int channels, enum AVCodecID *codec_id); + +/** + * Close the ALSA PCM. + * + * @param s1 media file handle + * + * @return 0 + */ +int ff_alsa_close(AVFormatContext *s1); + +/** + * Try to recover from ALSA buffer underrun. + * + * @param s1 media file handle + * @param err error code reported by the previous ALSA call + * + * @return 0 if OK, AVERROR_xxx on error + */ +int ff_alsa_xrun_recover(AVFormatContext *s1, int err); + +int ff_alsa_extend_reorder_buf(AlsaData *s, int size); + +#endif /* AVDEVICE_ALSA_H */ diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c new file mode 100644 index 0000000000..2cc5b7d574 --- /dev/null +++ b/libavdevice/alsa_dec.c @@ -0,0 +1,178 @@ +/* + * ALSA input and output + * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) + * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) + * + * 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 + */ + +/** + * @file + * ALSA input and output: input + * @author Luca Abeni ( lucabe72 email it ) + * @author Benoit Fouet ( benoit fouet free fr ) + * @author Nicolas George ( nicolas george normalesup org ) + * + * This avdevice decoder allows to capture audio from an ALSA (Advanced + * Linux Sound Architecture) device. + * + * The filename parameter is the name of an ALSA PCM device capable of + * capture, for example "default" or "plughw:1"; see the ALSA documentation + * for naming conventions. The empty string is equivalent to "default". + * + * The capture period is set to the lower value available for the device, + * which gives a low latency suitable for real-time capture. + * + * The PTS are an Unix time in microsecond. + * + * Due to a bug in the ALSA library + * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4308), this + * decoder does not work with certain ALSA plugins, especially the dsnoop + * plugin. + */ + +#include + +#include "libavutil/internal.h" +#include "libavutil/opt.h" + +#include "libavformat/avformat.h" +#include "libavformat/internal.h" + +#include "alsa.h" + +static av_cold int audio_read_header(AVFormatContext *s1) +{ + AlsaData *s = s1->priv_data; + AVStream *st; + int ret; + enum AVCodecID codec_id; + snd_pcm_sw_params_t *sw_params; + + st = avformat_new_stream(s1, NULL); + if (!st) { + av_log(s1, AV_LOG_ERROR, "Cannot add stream\n"); + + return AVERROR(ENOMEM); + } + codec_id = s1->audio_codec_id; + + ret = ff_alsa_open(s1, SND_PCM_STREAM_CAPTURE, &s->sample_rate, s->channels, + &codec_id); + if (ret < 0) { + return AVERROR(EIO); + } + + if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW) + av_log(s1, AV_LOG_WARNING, + "capture with some ALSA plugins, especially dsnoop, " + "may hang.\n"); + + ret = snd_pcm_sw_params_malloc(&sw_params); + if (ret < 0) { + av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n", + snd_strerror(ret)); + goto fail; + } + + snd_pcm_sw_params_current(s->h, sw_params); + snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE); + + ret = snd_pcm_sw_params(s->h, sw_params); + snd_pcm_sw_params_free(sw_params); + if (ret < 0) { + av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n", + snd_strerror(ret)); + goto fail; + } + + /* take real parameters */ + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = codec_id; + st->codec->sample_rate = s->sample_rate; + st->codec->channels = s->channels; + avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ + + return 0; + +fail: + snd_pcm_close(s->h); + return AVERROR(EIO); +} + +static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) +{ + AlsaData *s = s1->priv_data; + AVStream *st = s1->streams[0]; + int res; + snd_htimestamp_t timestamp; + snd_pcm_uframes_t ts_delay; + + if (av_new_packet(pkt, s->period_size) < 0) { + return AVERROR(EIO); + } + + while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) { + if (res == -EAGAIN) { + av_free_packet(pkt); + + return AVERROR(EAGAIN); + } + if (ff_alsa_xrun_recover(s1, res) < 0) { + av_log(s1, AV_LOG_ERROR, "ALSA read error: %s\n", + snd_strerror(res)); + av_free_packet(pkt); + + return AVERROR(EIO); + } + } + + snd_pcm_htimestamp(s->h, &ts_delay, ×tamp); + ts_delay += res; + pkt->pts = timestamp.tv_sec * 1000000LL + + (timestamp.tv_nsec * st->codec->sample_rate + - (int64_t)ts_delay * 1000000000LL + st->codec->sample_rate * 500LL) + / (st->codec->sample_rate * 1000LL); + + pkt->size = res * s->frame_size; + + return 0; +} + +static const AVOption options[] = { + { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass alsa_demuxer_class = { + .class_name = "ALSA demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_alsa_demuxer = { + .name = "alsa", + .long_name = NULL_IF_CONFIG_SMALL("ALSA audio input"), + .priv_data_size = sizeof(AlsaData), + .read_header = audio_read_header, + .read_packet = audio_read_packet, + .read_close = ff_alsa_close, + .flags = AVFMT_NOFILE, + .priv_class = &alsa_demuxer_class, +}; diff --git a/libavdevice/alsa_enc.c b/libavdevice/alsa_enc.c new file mode 100644 index 0000000000..30c1719203 --- /dev/null +++ b/libavdevice/alsa_enc.c @@ -0,0 +1,117 @@ +/* + * ALSA input and output + * Copyright (c) 2007 Luca Abeni ( lucabe72 email it ) + * Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr ) + * + * 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 + */ + +/** + * @file + * ALSA input and output: output + * @author Luca Abeni ( lucabe72 email it ) + * @author Benoit Fouet ( benoit fouet free fr ) + * + * This avdevice encoder allows to play audio to an ALSA (Advanced Linux + * Sound Architecture) device. + * + * The filename parameter is the name of an ALSA PCM device capable of + * capture, for example "default" or "plughw:1"; see the ALSA documentation + * for naming conventions. The empty string is equivalent to "default". + * + * The playback period is set to the lower value available for the device, + * which gives a low latency suitable for real-time playback. + */ + +#include + +#include "libavutil/internal.h" + +#include "libavformat/avformat.h" + +#include "alsa.h" + +static av_cold int audio_write_header(AVFormatContext *s1) +{ + AlsaData *s = s1->priv_data; + AVStream *st; + unsigned int sample_rate; + enum AVCodecID codec_id; + int res; + + st = s1->streams[0]; + sample_rate = st->codec->sample_rate; + codec_id = st->codec->codec_id; + res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, + st->codec->channels, &codec_id); + if (sample_rate != st->codec->sample_rate) { + av_log(s1, AV_LOG_ERROR, + "sample rate %d not available, nearest is %d\n", + st->codec->sample_rate, sample_rate); + goto fail; + } + + return res; + +fail: + snd_pcm_close(s->h); + return AVERROR(EIO); +} + +static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) +{ + AlsaData *s = s1->priv_data; + int res; + int size = pkt->size; + uint8_t *buf = pkt->data; + + size /= s->frame_size; + if (s->reorder_func) { + if (size > s->reorder_buf_size) + if (ff_alsa_extend_reorder_buf(s, size)) + return AVERROR(ENOMEM); + s->reorder_func(buf, s->reorder_buf, size); + buf = s->reorder_buf; + } + while ((res = snd_pcm_writei(s->h, buf, size)) < 0) { + if (res == -EAGAIN) { + + return AVERROR(EAGAIN); + } + + if (ff_alsa_xrun_recover(s1, res) < 0) { + av_log(s1, AV_LOG_ERROR, "ALSA write error: %s\n", + snd_strerror(res)); + + return AVERROR(EIO); + } + } + + return 0; +} + +AVOutputFormat ff_alsa_muxer = { + .name = "alsa", + .long_name = NULL_IF_CONFIG_SMALL("ALSA audio output"), + .priv_data_size = sizeof(AlsaData), + .audio_codec = DEFAULT_CODEC_ID, + .video_codec = AV_CODEC_ID_NONE, + .write_header = audio_write_header, + .write_packet = audio_write_packet, + .write_trailer = ff_alsa_close, + .flags = AVFMT_NOFILE, +}; diff --git a/libavdevice/jack.c b/libavdevice/jack.c new file mode 100644 index 0000000000..fc5caa8830 --- /dev/null +++ b/libavdevice/jack.c @@ -0,0 +1,353 @@ +/* + * JACK Audio Connection Kit input device + * Copyright (c) 2009 Samalyse + * Author: Olivier Guilyardi + * + * 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 "config.h" +#include +#include + +#include "libavutil/internal.h" +#include "libavutil/log.h" +#include "libavutil/fifo.h" +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +#include "libavformat/internal.h" +#include "timefilter.h" + +/** + * Size of the internal FIFO buffers as a number of audio packets + */ +#define FIFO_PACKETS_NUM 16 + +typedef struct JackData { + AVClass *class; + jack_client_t * client; + int activated; + sem_t packet_count; + jack_nframes_t sample_rate; + jack_nframes_t buffer_size; + jack_port_t ** ports; + int nports; + TimeFilter * timefilter; + AVFifoBuffer * new_pkts; + AVFifoBuffer * filled_pkts; + int pkt_xrun; + int jack_xrun; +} JackData; + +static int process_callback(jack_nframes_t nframes, void *arg) +{ + /* Warning: this function runs in realtime. One mustn't allocate memory here + * or do any other thing that could block. */ + + int i, j; + JackData *self = arg; + float * buffer; + jack_nframes_t latency, cycle_delay; + AVPacket pkt; + float *pkt_data; + double cycle_time; + + if (!self->client) + return 0; + + /* The approximate delay since the hardware interrupt as a number of frames */ + cycle_delay = jack_frames_since_cycle_start(self->client); + + /* Retrieve filtered cycle time */ + cycle_time = ff_timefilter_update(self->timefilter, + av_gettime() / 1000000.0 - (double) cycle_delay / self->sample_rate, + self->buffer_size); + + /* Check if an empty packet is available, and if there's enough space to send it back once filled */ + if ((av_fifo_size(self->new_pkts) < sizeof(pkt)) || (av_fifo_space(self->filled_pkts) < sizeof(pkt))) { + self->pkt_xrun = 1; + return 0; + } + + /* Retrieve empty (but allocated) packet */ + av_fifo_generic_read(self->new_pkts, &pkt, sizeof(pkt), NULL); + + pkt_data = (float *) pkt.data; + latency = 0; + + /* Copy and interleave audio data from the JACK buffer into the packet */ + for (i = 0; i < self->nports; i++) { + #if HAVE_JACK_PORT_GET_LATENCY_RANGE + jack_latency_range_t range; + jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); + latency += range.max; + #else + latency += jack_port_get_total_latency(self->client, self->ports[i]); + #endif + buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); + for (j = 0; j < self->buffer_size; j++) + pkt_data[j * self->nports + i] = buffer[j]; + } + + /* Timestamp the packet with the cycle start time minus the average latency */ + pkt.pts = (cycle_time - (double) latency / (self->nports * self->sample_rate)) * 1000000.0; + + /* Send the now filled packet back, and increase packet counter */ + av_fifo_generic_write(self->filled_pkts, &pkt, sizeof(pkt), NULL); + sem_post(&self->packet_count); + + return 0; +} + +static void shutdown_callback(void *arg) +{ + JackData *self = arg; + self->client = NULL; +} + +static int xrun_callback(void *arg) +{ + JackData *self = arg; + self->jack_xrun = 1; + ff_timefilter_reset(self->timefilter); + return 0; +} + +static int supply_new_packets(JackData *self, AVFormatContext *context) +{ + AVPacket pkt; + int test, pkt_size = self->buffer_size * self->nports * sizeof(float); + + /* Supply the process callback with new empty packets, by filling the new + * packets FIFO buffer with as many packets as possible. process_callback() + * can't do this by itself, because it can't allocate memory in realtime. */ + while (av_fifo_space(self->new_pkts) >= sizeof(pkt)) { + if ((test = av_new_packet(&pkt, pkt_size)) < 0) { + av_log(context, AV_LOG_ERROR, "Could not create packet of size %d\n", pkt_size); + return test; + } + av_fifo_generic_write(self->new_pkts, &pkt, sizeof(pkt), NULL); + } + return 0; +} + +static int start_jack(AVFormatContext *context) +{ + JackData *self = context->priv_data; + jack_status_t status; + int i, test; + double o, period; + + /* Register as a JACK client, using the context filename as client name. */ + self->client = jack_client_open(context->filename, JackNullOption, &status); + if (!self->client) { + av_log(context, AV_LOG_ERROR, "Unable to register as a JACK client\n"); + return AVERROR(EIO); + } + + sem_init(&self->packet_count, 0, 0); + + self->sample_rate = jack_get_sample_rate(self->client); + self->ports = av_malloc(self->nports * sizeof(*self->ports)); + self->buffer_size = jack_get_buffer_size(self->client); + + /* Register JACK ports */ + for (i = 0; i < self->nports; i++) { + char str[16]; + snprintf(str, sizeof(str), "input_%d", i + 1); + self->ports[i] = jack_port_register(self->client, str, + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + if (!self->ports[i]) { + av_log(context, AV_LOG_ERROR, "Unable to register port %s:%s\n", + context->filename, str); + jack_client_close(self->client); + return AVERROR(EIO); + } + } + + /* Register JACK callbacks */ + jack_set_process_callback(self->client, process_callback, self); + jack_on_shutdown(self->client, shutdown_callback, self); + jack_set_xrun_callback(self->client, xrun_callback, self); + + /* Create time filter */ + period = (double) self->buffer_size / self->sample_rate; + o = 2 * M_PI * 1.5 * period; /// bandwidth: 1.5Hz + self->timefilter = ff_timefilter_new (1.0 / self->sample_rate, sqrt(2 * o), o * o); + if (!self->timefilter) { + jack_client_close(self->client); + return AVERROR(ENOMEM); + } + + /* Create FIFO buffers */ + self->filled_pkts = av_fifo_alloc(FIFO_PACKETS_NUM * sizeof(AVPacket)); + /* New packets FIFO with one extra packet for safety against underruns */ + self->new_pkts = av_fifo_alloc((FIFO_PACKETS_NUM + 1) * sizeof(AVPacket)); + if ((test = supply_new_packets(self, context))) { + jack_client_close(self->client); + return test; + } + + return 0; + +} + +static void free_pkt_fifo(AVFifoBuffer *fifo) +{ + AVPacket pkt; + while (av_fifo_size(fifo)) { + av_fifo_generic_read(fifo, &pkt, sizeof(pkt), NULL); + av_free_packet(&pkt); + } + av_fifo_free(fifo); +} + +static void stop_jack(JackData *self) +{ + if (self->client) { + if (self->activated) + jack_deactivate(self->client); + jack_client_close(self->client); + } + sem_destroy(&self->packet_count); + free_pkt_fifo(self->new_pkts); + free_pkt_fifo(self->filled_pkts); + av_freep(&self->ports); + ff_timefilter_destroy(self->timefilter); +} + +static int audio_read_header(AVFormatContext *context) +{ + JackData *self = context->priv_data; + AVStream *stream; + int test; + + if ((test = start_jack(context))) + return test; + + stream = avformat_new_stream(context, NULL); + if (!stream) { + stop_jack(self); + return AVERROR(ENOMEM); + } + + stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; +#if HAVE_BIGENDIAN + stream->codec->codec_id = AV_CODEC_ID_PCM_F32BE; +#else + stream->codec->codec_id = AV_CODEC_ID_PCM_F32LE; +#endif + stream->codec->sample_rate = self->sample_rate; + stream->codec->channels = self->nports; + + avpriv_set_pts_info(stream, 64, 1, 1000000); /* 64 bits pts in us */ + return 0; +} + +static int audio_read_packet(AVFormatContext *context, AVPacket *pkt) +{ + JackData *self = context->priv_data; + struct timespec timeout = {0, 0}; + int test; + + /* Activate the JACK client on first packet read. Activating the JACK client + * means that process_callback() starts to get called at regular interval. + * If we activate it in audio_read_header(), we're actually reading audio data + * from the device before instructed to, and that may result in an overrun. */ + if (!self->activated) { + if (!jack_activate(self->client)) { + self->activated = 1; + av_log(context, AV_LOG_INFO, + "JACK client registered and activated (rate=%dHz, buffer_size=%d frames)\n", + self->sample_rate, self->buffer_size); + } else { + av_log(context, AV_LOG_ERROR, "Unable to activate JACK client\n"); + return AVERROR(EIO); + } + } + + /* Wait for a packet coming back from process_callback(), if one isn't available yet */ + timeout.tv_sec = av_gettime() / 1000000 + 2; + if (sem_timedwait(&self->packet_count, &timeout)) { + if (errno == ETIMEDOUT) { + av_log(context, AV_LOG_ERROR, + "Input error: timed out when waiting for JACK process callback output\n"); + } else { + char errbuf[128]; + int ret = AVERROR(errno); + av_strerror(ret, errbuf, sizeof(errbuf)); + av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n", + errbuf); + } + if (!self->client) + av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n"); + + return AVERROR(EIO); + } + + if (self->pkt_xrun) { + av_log(context, AV_LOG_WARNING, "Audio packet xrun\n"); + self->pkt_xrun = 0; + } + + if (self->jack_xrun) { + av_log(context, AV_LOG_WARNING, "JACK xrun\n"); + self->jack_xrun = 0; + } + + /* Retrieve the packet filled with audio data by process_callback() */ + av_fifo_generic_read(self->filled_pkts, pkt, sizeof(*pkt), NULL); + + if ((test = supply_new_packets(self, context))) + return test; + + return 0; +} + +static int audio_read_close(AVFormatContext *context) +{ + JackData *self = context->priv_data; + stop_jack(self); + return 0; +} + +#define OFFSET(x) offsetof(JackData, x) +static const AVOption options[] = { + { "channels", "Number of audio channels.", OFFSET(nports), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass jack_indev_class = { + .class_name = "JACK indev", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_jack_demuxer = { + .name = "jack", + .long_name = NULL_IF_CONFIG_SMALL("JACK Audio Connection Kit"), + .priv_data_size = sizeof(JackData), + .read_header = audio_read_header, + .read_packet = audio_read_packet, + .read_close = audio_read_close, + .flags = AVFMT_NOFILE, + .priv_class = &jack_indev_class, +}; diff --git a/libavdevice/jack_audio.c b/libavdevice/jack_audio.c deleted file mode 100644 index fc5caa8830..0000000000 --- a/libavdevice/jack_audio.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * JACK Audio Connection Kit input device - * Copyright (c) 2009 Samalyse - * Author: Olivier Guilyardi - * - * 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 "config.h" -#include -#include - -#include "libavutil/internal.h" -#include "libavutil/log.h" -#include "libavutil/fifo.h" -#include "libavutil/opt.h" -#include "libavutil/time.h" -#include "libavcodec/avcodec.h" -#include "libavformat/avformat.h" -#include "libavformat/internal.h" -#include "timefilter.h" - -/** - * Size of the internal FIFO buffers as a number of audio packets - */ -#define FIFO_PACKETS_NUM 16 - -typedef struct JackData { - AVClass *class; - jack_client_t * client; - int activated; - sem_t packet_count; - jack_nframes_t sample_rate; - jack_nframes_t buffer_size; - jack_port_t ** ports; - int nports; - TimeFilter * timefilter; - AVFifoBuffer * new_pkts; - AVFifoBuffer * filled_pkts; - int pkt_xrun; - int jack_xrun; -} JackData; - -static int process_callback(jack_nframes_t nframes, void *arg) -{ - /* Warning: this function runs in realtime. One mustn't allocate memory here - * or do any other thing that could block. */ - - int i, j; - JackData *self = arg; - float * buffer; - jack_nframes_t latency, cycle_delay; - AVPacket pkt; - float *pkt_data; - double cycle_time; - - if (!self->client) - return 0; - - /* The approximate delay since the hardware interrupt as a number of frames */ - cycle_delay = jack_frames_since_cycle_start(self->client); - - /* Retrieve filtered cycle time */ - cycle_time = ff_timefilter_update(self->timefilter, - av_gettime() / 1000000.0 - (double) cycle_delay / self->sample_rate, - self->buffer_size); - - /* Check if an empty packet is available, and if there's enough space to send it back once filled */ - if ((av_fifo_size(self->new_pkts) < sizeof(pkt)) || (av_fifo_space(self->filled_pkts) < sizeof(pkt))) { - self->pkt_xrun = 1; - return 0; - } - - /* Retrieve empty (but allocated) packet */ - av_fifo_generic_read(self->new_pkts, &pkt, sizeof(pkt), NULL); - - pkt_data = (float *) pkt.data; - latency = 0; - - /* Copy and interleave audio data from the JACK buffer into the packet */ - for (i = 0; i < self->nports; i++) { - #if HAVE_JACK_PORT_GET_LATENCY_RANGE - jack_latency_range_t range; - jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); - latency += range.max; - #else - latency += jack_port_get_total_latency(self->client, self->ports[i]); - #endif - buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); - for (j = 0; j < self->buffer_size; j++) - pkt_data[j * self->nports + i] = buffer[j]; - } - - /* Timestamp the packet with the cycle start time minus the average latency */ - pkt.pts = (cycle_time - (double) latency / (self->nports * self->sample_rate)) * 1000000.0; - - /* Send the now filled packet back, and increase packet counter */ - av_fifo_generic_write(self->filled_pkts, &pkt, sizeof(pkt), NULL); - sem_post(&self->packet_count); - - return 0; -} - -static void shutdown_callback(void *arg) -{ - JackData *self = arg; - self->client = NULL; -} - -static int xrun_callback(void *arg) -{ - JackData *self = arg; - self->jack_xrun = 1; - ff_timefilter_reset(self->timefilter); - return 0; -} - -static int supply_new_packets(JackData *self, AVFormatContext *context) -{ - AVPacket pkt; - int test, pkt_size = self->buffer_size * self->nports * sizeof(float); - - /* Supply the process callback with new empty packets, by filling the new - * packets FIFO buffer with as many packets as possible. process_callback() - * can't do this by itself, because it can't allocate memory in realtime. */ - while (av_fifo_space(self->new_pkts) >= sizeof(pkt)) { - if ((test = av_new_packet(&pkt, pkt_size)) < 0) { - av_log(context, AV_LOG_ERROR, "Could not create packet of size %d\n", pkt_size); - return test; - } - av_fifo_generic_write(self->new_pkts, &pkt, sizeof(pkt), NULL); - } - return 0; -} - -static int start_jack(AVFormatContext *context) -{ - JackData *self = context->priv_data; - jack_status_t status; - int i, test; - double o, period; - - /* Register as a JACK client, using the context filename as client name. */ - self->client = jack_client_open(context->filename, JackNullOption, &status); - if (!self->client) { - av_log(context, AV_LOG_ERROR, "Unable to register as a JACK client\n"); - return AVERROR(EIO); - } - - sem_init(&self->packet_count, 0, 0); - - self->sample_rate = jack_get_sample_rate(self->client); - self->ports = av_malloc(self->nports * sizeof(*self->ports)); - self->buffer_size = jack_get_buffer_size(self->client); - - /* Register JACK ports */ - for (i = 0; i < self->nports; i++) { - char str[16]; - snprintf(str, sizeof(str), "input_%d", i + 1); - self->ports[i] = jack_port_register(self->client, str, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - if (!self->ports[i]) { - av_log(context, AV_LOG_ERROR, "Unable to register port %s:%s\n", - context->filename, str); - jack_client_close(self->client); - return AVERROR(EIO); - } - } - - /* Register JACK callbacks */ - jack_set_process_callback(self->client, process_callback, self); - jack_on_shutdown(self->client, shutdown_callback, self); - jack_set_xrun_callback(self->client, xrun_callback, self); - - /* Create time filter */ - period = (double) self->buffer_size / self->sample_rate; - o = 2 * M_PI * 1.5 * period; /// bandwidth: 1.5Hz - self->timefilter = ff_timefilter_new (1.0 / self->sample_rate, sqrt(2 * o), o * o); - if (!self->timefilter) { - jack_client_close(self->client); - return AVERROR(ENOMEM); - } - - /* Create FIFO buffers */ - self->filled_pkts = av_fifo_alloc(FIFO_PACKETS_NUM * sizeof(AVPacket)); - /* New packets FIFO with one extra packet for safety against underruns */ - self->new_pkts = av_fifo_alloc((FIFO_PACKETS_NUM + 1) * sizeof(AVPacket)); - if ((test = supply_new_packets(self, context))) { - jack_client_close(self->client); - return test; - } - - return 0; - -} - -static void free_pkt_fifo(AVFifoBuffer *fifo) -{ - AVPacket pkt; - while (av_fifo_size(fifo)) { - av_fifo_generic_read(fifo, &pkt, sizeof(pkt), NULL); - av_free_packet(&pkt); - } - av_fifo_free(fifo); -} - -static void stop_jack(JackData *self) -{ - if (self->client) { - if (self->activated) - jack_deactivate(self->client); - jack_client_close(self->client); - } - sem_destroy(&self->packet_count); - free_pkt_fifo(self->new_pkts); - free_pkt_fifo(self->filled_pkts); - av_freep(&self->ports); - ff_timefilter_destroy(self->timefilter); -} - -static int audio_read_header(AVFormatContext *context) -{ - JackData *self = context->priv_data; - AVStream *stream; - int test; - - if ((test = start_jack(context))) - return test; - - stream = avformat_new_stream(context, NULL); - if (!stream) { - stop_jack(self); - return AVERROR(ENOMEM); - } - - stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; -#if HAVE_BIGENDIAN - stream->codec->codec_id = AV_CODEC_ID_PCM_F32BE; -#else - stream->codec->codec_id = AV_CODEC_ID_PCM_F32LE; -#endif - stream->codec->sample_rate = self->sample_rate; - stream->codec->channels = self->nports; - - avpriv_set_pts_info(stream, 64, 1, 1000000); /* 64 bits pts in us */ - return 0; -} - -static int audio_read_packet(AVFormatContext *context, AVPacket *pkt) -{ - JackData *self = context->priv_data; - struct timespec timeout = {0, 0}; - int test; - - /* Activate the JACK client on first packet read. Activating the JACK client - * means that process_callback() starts to get called at regular interval. - * If we activate it in audio_read_header(), we're actually reading audio data - * from the device before instructed to, and that may result in an overrun. */ - if (!self->activated) { - if (!jack_activate(self->client)) { - self->activated = 1; - av_log(context, AV_LOG_INFO, - "JACK client registered and activated (rate=%dHz, buffer_size=%d frames)\n", - self->sample_rate, self->buffer_size); - } else { - av_log(context, AV_LOG_ERROR, "Unable to activate JACK client\n"); - return AVERROR(EIO); - } - } - - /* Wait for a packet coming back from process_callback(), if one isn't available yet */ - timeout.tv_sec = av_gettime() / 1000000 + 2; - if (sem_timedwait(&self->packet_count, &timeout)) { - if (errno == ETIMEDOUT) { - av_log(context, AV_LOG_ERROR, - "Input error: timed out when waiting for JACK process callback output\n"); - } else { - char errbuf[128]; - int ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n", - errbuf); - } - if (!self->client) - av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n"); - - return AVERROR(EIO); - } - - if (self->pkt_xrun) { - av_log(context, AV_LOG_WARNING, "Audio packet xrun\n"); - self->pkt_xrun = 0; - } - - if (self->jack_xrun) { - av_log(context, AV_LOG_WARNING, "JACK xrun\n"); - self->jack_xrun = 0; - } - - /* Retrieve the packet filled with audio data by process_callback() */ - av_fifo_generic_read(self->filled_pkts, pkt, sizeof(*pkt), NULL); - - if ((test = supply_new_packets(self, context))) - return test; - - return 0; -} - -static int audio_read_close(AVFormatContext *context) -{ - JackData *self = context->priv_data; - stop_jack(self); - return 0; -} - -#define OFFSET(x) offsetof(JackData, x) -static const AVOption options[] = { - { "channels", "Number of audio channels.", OFFSET(nports), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { NULL }, -}; - -static const AVClass jack_indev_class = { - .class_name = "JACK indev", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVInputFormat ff_jack_demuxer = { - .name = "jack", - .long_name = NULL_IF_CONFIG_SMALL("JACK Audio Connection Kit"), - .priv_data_size = sizeof(JackData), - .read_header = audio_read_header, - .read_packet = audio_read_packet, - .read_close = audio_read_close, - .flags = AVFMT_NOFILE, - .priv_class = &jack_indev_class, -}; diff --git a/libavdevice/oss.c b/libavdevice/oss.c new file mode 100644 index 0000000000..eb8d454422 --- /dev/null +++ b/libavdevice/oss.c @@ -0,0 +1,139 @@ +/* + * Linux audio play and grab interface + * Copyright (c) 2000, 2001 Fabrice Bellard + * + * 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 "config.h" + +#include + +#if HAVE_SOUNDCARD_H +#include +#else +#include +#endif + +#include +#include +#include + +#include "libavutil/log.h" + +#include "libavcodec/avcodec.h" + +#include "libavformat/avformat.h" + +#include "oss.h" + +int ff_oss_audio_open(AVFormatContext *s1, int is_output, + const char *audio_device) +{ + OSSAudioData *s = s1->priv_data; + int audio_fd; + int tmp, err; + char *flip = getenv("AUDIO_FLIP_LEFT"); + char errbuff[128]; + + if (is_output) + audio_fd = avpriv_open(audio_device, O_WRONLY); + else + audio_fd = avpriv_open(audio_device, O_RDONLY); + if (audio_fd < 0) { + av_log(s1, AV_LOG_ERROR, "%s: %s\n", audio_device, strerror(errno)); + return AVERROR(EIO); + } + + if (flip && *flip == '1') { + s->flip_left = 1; + } + + /* non blocking mode */ + if (!is_output) + fcntl(audio_fd, F_SETFL, O_NONBLOCK); + + s->frame_size = OSS_AUDIO_BLOCK_SIZE; + +#define CHECK_IOCTL_ERROR(event) \ + if (err < 0) { \ + av_strerror(AVERROR(errno), errbuff, sizeof(errbuff)); \ + av_log(s1, AV_LOG_ERROR, #event ": %s\n", errbuff); \ + goto fail; \ + } + + /* select format : favour native format + * We don't CHECK_IOCTL_ERROR here because even if failed OSS still may be + * usable. If OSS is not usable the SNDCTL_DSP_SETFMTS later is going to + * fail anyway. */ + (void) ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp); + +#if HAVE_BIGENDIAN + if (tmp & AFMT_S16_BE) { + tmp = AFMT_S16_BE; + } else if (tmp & AFMT_S16_LE) { + tmp = AFMT_S16_LE; + } else { + tmp = 0; + } +#else + if (tmp & AFMT_S16_LE) { + tmp = AFMT_S16_LE; + } else if (tmp & AFMT_S16_BE) { + tmp = AFMT_S16_BE; + } else { + tmp = 0; + } +#endif + + switch(tmp) { + case AFMT_S16_LE: + s->codec_id = AV_CODEC_ID_PCM_S16LE; + break; + case AFMT_S16_BE: + s->codec_id = AV_CODEC_ID_PCM_S16BE; + break; + default: + av_log(s1, AV_LOG_ERROR, "Soundcard does not support 16 bit sample format\n"); + close(audio_fd); + return AVERROR(EIO); + } + err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp); + CHECK_IOCTL_ERROR(SNDCTL_DSP_SETFMTS) + + tmp = (s->channels == 2); + err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); + CHECK_IOCTL_ERROR(SNDCTL_DSP_STEREO) + + tmp = s->sample_rate; + err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp); + CHECK_IOCTL_ERROR(SNDCTL_DSP_SPEED) + s->sample_rate = tmp; /* store real sample rate */ + s->fd = audio_fd; + + return 0; + fail: + close(audio_fd); + return AVERROR(EIO); +#undef CHECK_IOCTL_ERROR +} + +int ff_oss_audio_close(OSSAudioData *s) +{ + close(s->fd); + return 0; +} diff --git a/libavdevice/oss.h b/libavdevice/oss.h new file mode 100644 index 0000000000..0fbe14b3ec --- /dev/null +++ b/libavdevice/oss.h @@ -0,0 +1,45 @@ +/* + * 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_OSS_H +#define AVDEVICE_OSS_H + +#include "libavcodec/avcodec.h" + +#include "libavformat/avformat.h" + +#define OSS_AUDIO_BLOCK_SIZE 4096 + +typedef struct OSSAudioData { + AVClass *class; + int fd; + int sample_rate; + int channels; + int frame_size; /* in bytes ! */ + enum AVCodecID codec_id; + unsigned int flip_left : 1; + uint8_t buffer[OSS_AUDIO_BLOCK_SIZE]; + int buffer_ptr; +} OSSAudioData; + +int ff_oss_audio_open(AVFormatContext *s1, int is_output, + const char *audio_device); + +int ff_oss_audio_close(OSSAudioData *s); + +#endif /* AVDEVICE_OSS_H */ diff --git a/libavdevice/oss_audio.c b/libavdevice/oss_audio.c deleted file mode 100644 index 4feb937134..0000000000 --- a/libavdevice/oss_audio.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Linux audio play and grab interface - * Copyright (c) 2000, 2001 Fabrice Bellard - * - * 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 "config.h" - -#include - -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - -#include -#include -#include - -#include "libavutil/log.h" - -#include "libavcodec/avcodec.h" - -#include "libavformat/avformat.h" - -#include "oss_audio.h" - -int ff_oss_audio_open(AVFormatContext *s1, int is_output, - const char *audio_device) -{ - OSSAudioData *s = s1->priv_data; - int audio_fd; - int tmp, err; - char *flip = getenv("AUDIO_FLIP_LEFT"); - char errbuff[128]; - - if (is_output) - audio_fd = avpriv_open(audio_device, O_WRONLY); - else - audio_fd = avpriv_open(audio_device, O_RDONLY); - if (audio_fd < 0) { - av_log(s1, AV_LOG_ERROR, "%s: %s\n", audio_device, strerror(errno)); - return AVERROR(EIO); - } - - if (flip && *flip == '1') { - s->flip_left = 1; - } - - /* non blocking mode */ - if (!is_output) - fcntl(audio_fd, F_SETFL, O_NONBLOCK); - - s->frame_size = OSS_AUDIO_BLOCK_SIZE; - -#define CHECK_IOCTL_ERROR(event) \ - if (err < 0) { \ - av_strerror(AVERROR(errno), errbuff, sizeof(errbuff)); \ - av_log(s1, AV_LOG_ERROR, #event ": %s\n", errbuff); \ - goto fail; \ - } - - /* select format : favour native format - * We don't CHECK_IOCTL_ERROR here because even if failed OSS still may be - * usable. If OSS is not usable the SNDCTL_DSP_SETFMTS later is going to - * fail anyway. */ - (void) ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp); - -#if HAVE_BIGENDIAN - if (tmp & AFMT_S16_BE) { - tmp = AFMT_S16_BE; - } else if (tmp & AFMT_S16_LE) { - tmp = AFMT_S16_LE; - } else { - tmp = 0; - } -#else - if (tmp & AFMT_S16_LE) { - tmp = AFMT_S16_LE; - } else if (tmp & AFMT_S16_BE) { - tmp = AFMT_S16_BE; - } else { - tmp = 0; - } -#endif - - switch(tmp) { - case AFMT_S16_LE: - s->codec_id = AV_CODEC_ID_PCM_S16LE; - break; - case AFMT_S16_BE: - s->codec_id = AV_CODEC_ID_PCM_S16BE; - break; - default: - av_log(s1, AV_LOG_ERROR, "Soundcard does not support 16 bit sample format\n"); - close(audio_fd); - return AVERROR(EIO); - } - err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp); - CHECK_IOCTL_ERROR(SNDCTL_DSP_SETFMTS) - - tmp = (s->channels == 2); - err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); - CHECK_IOCTL_ERROR(SNDCTL_DSP_STEREO) - - tmp = s->sample_rate; - err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp); - CHECK_IOCTL_ERROR(SNDCTL_DSP_SPEED) - s->sample_rate = tmp; /* store real sample rate */ - s->fd = audio_fd; - - return 0; - fail: - close(audio_fd); - return AVERROR(EIO); -#undef CHECK_IOCTL_ERROR -} - -int ff_oss_audio_close(OSSAudioData *s) -{ - close(s->fd); - return 0; -} diff --git a/libavdevice/oss_audio.h b/libavdevice/oss_audio.h deleted file mode 100644 index 87ac4adfd5..0000000000 --- a/libavdevice/oss_audio.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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_OSS_AUDIO_H -#define AVDEVICE_OSS_AUDIO_H - -#include "libavcodec/avcodec.h" - -#include "libavformat/avformat.h" - -#define OSS_AUDIO_BLOCK_SIZE 4096 - -typedef struct OSSAudioData { - AVClass *class; - int fd; - int sample_rate; - int channels; - int frame_size; /* in bytes ! */ - enum AVCodecID codec_id; - unsigned int flip_left : 1; - uint8_t buffer[OSS_AUDIO_BLOCK_SIZE]; - int buffer_ptr; -} OSSAudioData; - -int ff_oss_audio_open(AVFormatContext *s1, int is_output, - const char *audio_device); - -int ff_oss_audio_close(OSSAudioData *s); - -#endif /* AVDEVICE_OSS_AUDIO_H */ diff --git a/libavdevice/oss_audio_dec.c b/libavdevice/oss_audio_dec.c deleted file mode 100644 index 601d91c31f..0000000000 --- a/libavdevice/oss_audio_dec.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Linux audio play interface - * Copyright (c) 2000, 2001 Fabrice Bellard - * - * 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 "config.h" - -#include - -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - -#include -#include -#include - -#include "libavutil/internal.h" -#include "libavutil/opt.h" -#include "libavutil/time.h" - -#include "libavcodec/avcodec.h" - -#include "libavformat/avformat.h" -#include "libavformat/internal.h" - -#include "oss_audio.h" - -static int audio_read_header(AVFormatContext *s1) -{ - OSSAudioData *s = s1->priv_data; - AVStream *st; - int ret; - - st = avformat_new_stream(s1, NULL); - if (!st) { - return AVERROR(ENOMEM); - } - - ret = ff_oss_audio_open(s1, 0, s1->filename); - if (ret < 0) { - return AVERROR(EIO); - } - - /* 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; - - avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - return 0; -} - -static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - OSSAudioData *s = s1->priv_data; - int ret, bdelay; - int64_t cur_time; - struct audio_buf_info abufi; - - if ((ret=av_new_packet(pkt, s->frame_size)) < 0) - return ret; - - ret = read(s->fd, pkt->data, pkt->size); - if (ret <= 0){ - av_free_packet(pkt); - pkt->size = 0; - if (ret<0) return AVERROR(errno); - else return AVERROR_EOF; - } - 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; - } - /* subtract 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; - - 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; -} - -static int audio_read_close(AVFormatContext *s1) -{ - OSSAudioData *s = s1->priv_data; - - ff_oss_audio_close(s); - return 0; -} - -static const AVOption options[] = { - { "sample_rate", "", offsetof(OSSAudioData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { "channels", "", offsetof(OSSAudioData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, - { NULL }, -}; - -static const AVClass oss_demuxer_class = { - .class_name = "OSS demuxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVInputFormat ff_oss_demuxer = { - .name = "oss", - .long_name = NULL_IF_CONFIG_SMALL("OSS (Open Sound System) capture"), - .priv_data_size = sizeof(OSSAudioData), - .read_header = audio_read_header, - .read_packet = audio_read_packet, - .read_close = audio_read_close, - .flags = AVFMT_NOFILE, - .priv_class = &oss_demuxer_class, -}; diff --git a/libavdevice/oss_audio_enc.c b/libavdevice/oss_audio_enc.c deleted file mode 100644 index 688982a00f..0000000000 --- a/libavdevice/oss_audio_enc.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Linux audio grab interface - * Copyright (c) 2000, 2001 Fabrice Bellard - * - * 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 "config.h" - -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - -#include -#include -#include - -#include "libavutil/internal.h" - -#include "libavcodec/avcodec.h" - -#include "libavformat/avformat.h" -#include "libavformat/internal.h" - -#include "oss_audio.h" - -static int audio_write_header(AVFormatContext *s1) -{ - OSSAudioData *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_oss_audio_open(s1, 1, s1->filename); - if (ret < 0) { - return AVERROR(EIO); - } else { - return 0; - } -} - -static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) -{ - OSSAudioData *s = s1->priv_data; - int len, ret; - int size= pkt->size; - uint8_t *buf= pkt->data; - - while (size > 0) { - len = FFMIN(OSS_AUDIO_BLOCK_SIZE - s->buffer_ptr, size); - memcpy(s->buffer + s->buffer_ptr, buf, len); - s->buffer_ptr += len; - if (s->buffer_ptr >= OSS_AUDIO_BLOCK_SIZE) { - for(;;) { - ret = write(s->fd, s->buffer, OSS_AUDIO_BLOCK_SIZE); - if (ret > 0) - break; - if (ret < 0 && (errno != EAGAIN && errno != EINTR)) - return AVERROR(EIO); - } - s->buffer_ptr = 0; - } - buf += len; - size -= len; - } - return 0; -} - -static int audio_write_trailer(AVFormatContext *s1) -{ - OSSAudioData *s = s1->priv_data; - - ff_oss_audio_close(s); - return 0; -} - -AVOutputFormat ff_oss_muxer = { - .name = "oss", - .long_name = NULL_IF_CONFIG_SMALL("OSS (Open Sound System) playback"), - .priv_data_size = sizeof(OSSAudioData), - /* 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(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), - .video_codec = AV_CODEC_ID_NONE, - .write_header = audio_write_header, - .write_packet = audio_write_packet, - .write_trailer = audio_write_trailer, - .flags = AVFMT_NOFILE, -}; diff --git a/libavdevice/oss_dec.c b/libavdevice/oss_dec.c new file mode 100644 index 0000000000..3f786cc356 --- /dev/null +++ b/libavdevice/oss_dec.c @@ -0,0 +1,146 @@ +/* + * Linux audio play interface + * Copyright (c) 2000, 2001 Fabrice Bellard + * + * 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 "config.h" + +#include + +#if HAVE_SOUNDCARD_H +#include +#else +#include +#endif + +#include +#include +#include + +#include "libavutil/internal.h" +#include "libavutil/opt.h" +#include "libavutil/time.h" + +#include "libavcodec/avcodec.h" + +#include "libavformat/avformat.h" +#include "libavformat/internal.h" + +#include "oss.h" + +static int audio_read_header(AVFormatContext *s1) +{ + OSSAudioData *s = s1->priv_data; + AVStream *st; + int ret; + + st = avformat_new_stream(s1, NULL); + if (!st) { + return AVERROR(ENOMEM); + } + + ret = ff_oss_audio_open(s1, 0, s1->filename); + if (ret < 0) { + return AVERROR(EIO); + } + + /* 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; + + avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ + return 0; +} + +static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) +{ + OSSAudioData *s = s1->priv_data; + int ret, bdelay; + int64_t cur_time; + struct audio_buf_info abufi; + + if ((ret=av_new_packet(pkt, s->frame_size)) < 0) + return ret; + + ret = read(s->fd, pkt->data, pkt->size); + if (ret <= 0){ + av_free_packet(pkt); + pkt->size = 0; + if (ret<0) return AVERROR(errno); + else return AVERROR_EOF; + } + 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; + } + /* subtract 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; + + 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; +} + +static int audio_read_close(AVFormatContext *s1) +{ + OSSAudioData *s = s1->priv_data; + + ff_oss_audio_close(s); + return 0; +} + +static const AVOption options[] = { + { "sample_rate", "", offsetof(OSSAudioData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { "channels", "", offsetof(OSSAudioData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass oss_demuxer_class = { + .class_name = "OSS demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_oss_demuxer = { + .name = "oss", + .long_name = NULL_IF_CONFIG_SMALL("OSS (Open Sound System) capture"), + .priv_data_size = sizeof(OSSAudioData), + .read_header = audio_read_header, + .read_packet = audio_read_packet, + .read_close = audio_read_close, + .flags = AVFMT_NOFILE, + .priv_class = &oss_demuxer_class, +}; diff --git a/libavdevice/oss_enc.c b/libavdevice/oss_enc.c new file mode 100644 index 0000000000..2f075589a9 --- /dev/null +++ b/libavdevice/oss_enc.c @@ -0,0 +1,108 @@ +/* + * Linux audio grab interface + * Copyright (c) 2000, 2001 Fabrice Bellard + * + * 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 "config.h" + +#if HAVE_SOUNDCARD_H +#include +#else +#include +#endif + +#include +#include +#include + +#include "libavutil/internal.h" + +#include "libavcodec/avcodec.h" + +#include "libavformat/avformat.h" +#include "libavformat/internal.h" + +#include "oss.h" + +static int audio_write_header(AVFormatContext *s1) +{ + OSSAudioData *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_oss_audio_open(s1, 1, s1->filename); + if (ret < 0) { + return AVERROR(EIO); + } else { + return 0; + } +} + +static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) +{ + OSSAudioData *s = s1->priv_data; + int len, ret; + int size= pkt->size; + uint8_t *buf= pkt->data; + + while (size > 0) { + len = FFMIN(OSS_AUDIO_BLOCK_SIZE - s->buffer_ptr, size); + memcpy(s->buffer + s->buffer_ptr, buf, len); + s->buffer_ptr += len; + if (s->buffer_ptr >= OSS_AUDIO_BLOCK_SIZE) { + for(;;) { + ret = write(s->fd, s->buffer, OSS_AUDIO_BLOCK_SIZE); + if (ret > 0) + break; + if (ret < 0 && (errno != EAGAIN && errno != EINTR)) + return AVERROR(EIO); + } + s->buffer_ptr = 0; + } + buf += len; + size -= len; + } + return 0; +} + +static int audio_write_trailer(AVFormatContext *s1) +{ + OSSAudioData *s = s1->priv_data; + + ff_oss_audio_close(s); + return 0; +} + +AVOutputFormat ff_oss_muxer = { + .name = "oss", + .long_name = NULL_IF_CONFIG_SMALL("OSS (Open Sound System) playback"), + .priv_data_size = sizeof(OSSAudioData), + /* 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(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), + .video_codec = AV_CODEC_ID_NONE, + .write_header = audio_write_header, + .write_packet = audio_write_packet, + .write_trailer = audio_write_trailer, + .flags = AVFMT_NOFILE, +}; diff --git a/libavdevice/sndio.c b/libavdevice/sndio.c new file mode 100644 index 0000000000..739551b841 --- /dev/null +++ b/libavdevice/sndio.c @@ -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 +#include + +#include "libavformat/avformat.h" + +#include "libavdevice/sndio.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 || + (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 ? AV_CODEC_ID_PCM_S16LE : AV_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; +} diff --git a/libavdevice/sndio.h b/libavdevice/sndio.h new file mode 100644 index 0000000000..cd5c55ecc5 --- /dev/null +++ b/libavdevice/sndio.h @@ -0,0 +1,48 @@ +/* + * 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_H +#define AVDEVICE_SNDIO_H + +#include +#include + +#include "libavformat/avformat.h" +#include "libavutil/log.h" + +typedef struct SndioData { + AVClass *class; + struct sio_hdl *hdl; + enum AVCodecID 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_H */ diff --git a/libavdevice/sndio_common.c b/libavdevice/sndio_common.c deleted file mode 100644 index 1bea6c5be1..0000000000 --- a/libavdevice/sndio_common.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 -#include - -#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 || - (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 ? AV_CODEC_ID_PCM_S16LE : AV_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; -} diff --git a/libavdevice/sndio_common.h b/libavdevice/sndio_common.h deleted file mode 100644 index 2f70213aed..0000000000 --- a/libavdevice/sndio_common.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 -#include - -#include "libavformat/avformat.h" -#include "libavutil/log.h" - -typedef struct SndioData { - AVClass *class; - struct sio_hdl *hdl; - enum AVCodecID 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 */ diff --git a/libavdevice/sndio_dec.c b/libavdevice/sndio_dec.c index 24c6d1e7da..7ebb8c3ccc 100644 --- a/libavdevice/sndio_dec.c +++ b/libavdevice/sndio_dec.c @@ -29,7 +29,7 @@ #include "libavformat/avformat.h" #include "libavformat/internal.h" -#include "sndio_common.h" +#include "libavdevice/sndio.h" static av_cold int audio_read_header(AVFormatContext *s1) { diff --git a/libavdevice/sndio_enc.c b/libavdevice/sndio_enc.c index 61ac398a84..fad361062b 100644 --- a/libavdevice/sndio_enc.c +++ b/libavdevice/sndio_enc.c @@ -26,7 +26,7 @@ #include "libavformat/avformat.h" -#include "sndio_common.h" +#include "libavdevice/sndio.h" static av_cold int audio_write_header(AVFormatContext *s1) { -- cgit v1.2.3