Commit 65eae2a7 authored by Jonathan Baldwin's avatar Jonathan Baldwin Committed by Stefano Sabatini

lavdev: add openal input device

parent cdeb803e
Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version next:
- openal input device added
version 0.8:
......
......@@ -188,6 +188,7 @@ External library support:
--enable-libxavs enable AVS encoding via xavs [no]
--enable-libxvid enable Xvid encoding via xvidcore,
native MPEG-4/Xvid encoder exists [no]
--enable-openal enable OpenAL 1.1 capture support [no]
--enable-mlib enable Sun medialib [no]
--enable-zlib enable zlib [autodetect]
......@@ -959,6 +960,7 @@ CONFIG_LIST="
mpegaudiodsp
network
nonfree
openal
pic
postproc
rdft
......@@ -1471,6 +1473,7 @@ dv1394_indev_deps="dv1394 dv_demuxer"
fbdev_indev_deps="linux_fb_h"
jack_indev_deps="jack_jack_h sem_timedwait"
libdc1394_indev_deps="libdc1394"
openal_indev_deps="openal"
oss_indev_deps_any="soundcard_h sys_soundcard_h"
oss_outdev_deps_any="soundcard_h sys_soundcard_h"
sdl_outdev_deps="sdl"
......@@ -2948,6 +2951,11 @@ enabled libx264 && require libx264 x264.h x264_encoder_encode -lx264 &&
die "ERROR: libx264 version must be >= 0.115."; }
enabled libxavs && require libxavs xavs.h xavs_encoder_encode -lxavs
enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore
enabled openal && { { for al_libs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
check_lib 'AL/al.h' alGetError "${al_libs}" && break; done } ||
die "ERROR: openal not found"; } &&
{ check_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" ||
die "ERROR: openal version must be 1.1 or compatible"; }
enabled mlib && require mediaLib mlib_types.h mlib_VectorSub_S16_U8_Mod -lmlib
SDL_CONFIG="${cross_prefix}sdl-config"
......@@ -3247,6 +3255,7 @@ echo "libvpx enabled ${libvpx-no}"
echo "libx264 enabled ${libx264-no}"
echo "libxavs enabled ${libxavs-no}"
echo "libxvid enabled ${libxvid-no}"
echo "openal enabled ${openal-no}"
echo "zlib enabled ${zlib-no}"
echo "bzlib enabled ${bzlib-no}"
echo
......
......@@ -137,6 +137,95 @@ For more information read:
IIDC1394 input device, based on libdc1394 and libraw1394.
@section openal
The OpenAL input device provides audio capture on all systems with a
working OpenAL 1.1 implementation.
To enable this input device during configuration, you need OpenAL
headers and libraries installed on your system, and need to configure
FFmpeg with @code{--enable-openal}.
OpenAL headers and libraries should be provided as part of your OpenAL
implementation, or as an additional download (an SDK). Depending on your
installation you may need to specify additional flags via the
@code{--extra-cflags} and @code{--extra-ldflags} for allowing the build
system to locate the OpenAL headers and libraries.
An incomplete list of OpenAL implementations follows:
@table @strong
@item Creative
The official Windows implementation, providing hardware acceleration
with supported devices and software fallback.
See @url{http://openal.org/}.
@item OpenAL Soft
Portable, open source (LGPL) software implementation. Includes
backends for the most common sound APIs on the Windows, Linux,
Solaris, and BSD operating systems.
See @url{http://kcat.strangesoft.net/openal.html}.
@item Apple
OpenAL is part of Core Audio, the official Mac OS X Audio interface.
See @url{http://developer.apple.com/technologies/mac/audio-and-video.html}
@end table
This device allows to capture from an audio input device handled
through OpenAL.
You need to specify the name of the device to capture in the provided
filename. If the empty string is provided, the device will
automatically select the default device. You can get the list of the
supported devices by using the option @var{list_devices}.
@subsection Options
@table @option
@item channels
Set the number of channels in the captured audio. Only the values
@option{1} (monaural) and @option{2} (stereo) are currently supported.
Defaults to @option{2}.
@item sample_size
Set the sample size (in bits) of the captured audio. Only the values
@option{8} and @option{16} are currently supported. Defaults to
@option{16}.
@item sample_rate
Set the sample rate (in Hz) of the captured audio.
Defaults to @option{44.1k}.
@item list_devices
If set to @option{true}, print a list of devices and exit.
Defaults to @option{false}.
@end table
@subsection Examples
Print the list of OpenAL supported devices and exit:
@example
$ ffmpeg -list_devices true -f openal -i dummy out.ogg
@end example
Capture from the OpenAL device @file{DR-BT101 via PulseAudio}:
@example
$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out.ogg
@end example
Capture from the default device (note the empty string '' as filename):
@example
$ ffmpeg -f openal -i '' out.ogg
@end example
Capture from two devices simultaneously, writing to two different files,
within the same @file{ffmpeg} command:
@example
$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out1.ogg -f openal -i 'ALSA Default' out2.ogg
@end example
Note: not all OpenAL implementations support multiple simultaneous capture -
try the latest OpenAL Soft if the above does not work.
@section oss
Open Sound System input device.
......
......@@ -19,6 +19,7 @@ OBJS-$(CONFIG_DSHOW_INDEV) += dshow.o dshow_enummediatypes.o \
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
OBJS-$(CONFIG_FBDEV_INDEV) += fbdev.o
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o
OBJS-$(CONFIG_OPENAL_INDEV) += openal-dec.o
OBJS-$(CONFIG_OSS_INDEV) += oss_audio.o
OBJS-$(CONFIG_OSS_OUTDEV) += oss_audio.o
OBJS-$(CONFIG_SDL_OUTDEV) += sdl.o
......
......@@ -44,6 +44,7 @@ void avdevice_register_all(void)
REGISTER_INDEV (DV1394, dv1394);
REGISTER_INDEV (FBDEV, fbdev);
REGISTER_INDEV (JACK, jack);
REGISTER_INDEV (OPENAL, openal);
REGISTER_INOUTDEV (OSS, oss);
REGISTER_OUTDEV (SDL, sdl);
REGISTER_INOUTDEV (SNDIO, sndio);
......
......@@ -23,8 +23,8 @@
#include "libavformat/avformat.h"
#define LIBAVDEVICE_VERSION_MAJOR 53
#define LIBAVDEVICE_VERSION_MINOR 1
#define LIBAVDEVICE_VERSION_MICRO 1
#define LIBAVDEVICE_VERSION_MINOR 2
#define LIBAVDEVICE_VERSION_MICRO 0
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \
......
/*
* Copyright (c) 2011 Jonathan Baldwin
*
* This file is part of FFmpeg.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @file
* OpenAL 1.1 capture device for libavdevice
**/
#include <AL/al.h>
#include <AL/alc.h>
#include "libavutil/opt.h"
#include "avdevice.h"
typedef struct {
AVClass *class;
/** OpenAL capture device context. **/
ALCdevice *device;
/** The number of channels in the captured audio. **/
int channels;
/** The sample rate (in Hz) of the captured audio. **/
int sample_rate;
/** The sample size (in bits) of the captured audio. **/
int sample_size;
/** The OpenAL sample format of the captured audio. **/
ALCenum sample_format;
/** The number of bytes between two consecutive samples of the same channel/component. **/
ALCint sample_step;
/** If true, print a list of capture devices on this system and exit. **/
int list_devices;
} al_data;
typedef struct {
ALCenum al_fmt;
enum CodecID codec_id;
int channels;
} al_format_info;
#define LOWEST_AL_FORMAT FFMIN(FFMIN(AL_FORMAT_MONO8,AL_FORMAT_MONO16),FFMIN(AL_FORMAT_STEREO8,AL_FORMAT_STEREO16))
/**
* Get information about an AL_FORMAT value.
* @param al_fmt the AL_FORMAT value to find information about.
* @return A pointer to a structure containing information about the AL_FORMAT value.
*/
static inline al_format_info* get_al_format_info(ALCenum al_fmt)
{
static al_format_info info_table[] = {
[AL_FORMAT_MONO8-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO8, CODEC_ID_PCM_U8, 1},
[AL_FORMAT_MONO16-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO16, AV_NE (CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE), 1},
[AL_FORMAT_STEREO8-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO8, CODEC_ID_PCM_U8, 2},
[AL_FORMAT_STEREO16-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO16, AV_NE (CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE), 2},
};
return &info_table[al_fmt-LOWEST_AL_FORMAT];
}
/**
* Get the OpenAL error code, translated into an av/errno error code.
* @param device The ALC device to check for errors.
* @param error_msg_ret A pointer to a char* in which to return the error message, or NULL if desired.
* @return The error code, or 0 if there is no error.
*/
static inline int al_get_error(ALCdevice *device, const char** error_msg_ret)
{
ALCenum error = alcGetError(device);
if (error_msg_ret)
*error_msg_ret = (const char*) alcGetString(device, error);
switch (error) {
case ALC_NO_ERROR:
return 0;
case ALC_INVALID_DEVICE:
return AVERROR(ENODEV);
break;
case ALC_INVALID_CONTEXT:
case ALC_INVALID_ENUM:
case ALC_INVALID_VALUE:
return AVERROR(EINVAL);
break;
case ALC_OUT_OF_MEMORY:
return AVERROR(ENOMEM);
break;
default:
return AVERROR(EIO);
}
}
/**
* Print out a list of OpenAL capture devices on this system.
*/
static inline void print_al_capture_devices(void *log_ctx)
{
const char *devices;
if (!(devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)))
return;
av_log(log_ctx, AV_LOG_INFO, "List of OpenAL capture devices on this system:\n");
for (; *devices != '\0'; devices += strlen(devices) + 1)
av_log(log_ctx, AV_LOG_INFO, " %s\n", devices);
}
static int read_header(AVFormatContext *ctx, AVFormatParameters *ap)
{
al_data *ad = ctx->priv_data;
static const ALCenum sample_formats[2][2] = {
{ AL_FORMAT_MONO8, AL_FORMAT_STEREO8 },
{ AL_FORMAT_MONO16, AL_FORMAT_STEREO16 }
};
int error = 0;
const char *error_msg;
AVStream *st = NULL;
AVCodecContext *codec = NULL;
if (ad->list_devices) {
print_al_capture_devices(ctx);
return AVERROR_EXIT;
}
ad->sample_format = sample_formats[ad->sample_size/8-1][ad->channels-1];
/* Open device for capture */
ad->device =
alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL,
ad->sample_rate,
ad->sample_format,
ad->sample_rate); /* Maximum 1 second of sample data to be read at once */
if (error = al_get_error(ad->device, &error_msg)) goto fail;
/* Create stream */
if (!(st = av_new_stream(ctx, 0))) {
error = AVERROR(ENOMEM);
goto fail;
}
/* We work in microseconds */
av_set_pts_info(st, 64, 1, 1000000);
/* Set codec parameters */
codec = st->codec;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
codec->sample_rate = ad->sample_rate;
codec->channels = get_al_format_info(ad->sample_format)->channels;
codec->codec_id = get_al_format_info(ad->sample_format)->codec_id;
/* This is needed to read the audio data */
ad->sample_step = (av_get_bits_per_sample(get_al_format_info(ad->sample_format)->codec_id) *
get_al_format_info(ad->sample_format)->channels) / 8;
/* Finally, start the capture process */
alcCaptureStart(ad->device);
return 0;
fail:
/* Handle failure */
if (ad->device)
alcCaptureCloseDevice(ad->device);
if (error_msg)
av_log(ctx, AV_LOG_ERROR, "Cannot open device: %s\n", error_msg);
return error;
}
static int read_packet(AVFormatContext* ctx, AVPacket *pkt)
{
al_data *ad = ctx->priv_data;
int error=0;
const char *error_msg;
ALCint nb_samples;
/* Get number of samples available */
alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples);
if (error = al_get_error(ad->device, &error_msg)) goto fail;
/* Create a packet of appropriate size */
av_new_packet(pkt, nb_samples*ad->sample_step);
pkt->pts = av_gettime();
/* Fill the packet with the available samples */
alcCaptureSamples(ad->device, pkt->data, nb_samples);
if (error = al_get_error(ad->device, &error_msg)) goto fail;
return pkt->size;
fail:
/* Handle failure */
if (pkt->data)
av_destruct_packet(pkt);
if (error_msg)
av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg);
return error;
}
static int read_close(AVFormatContext* ctx)
{
al_data *ad = ctx->priv_data;
if (ad->device) {
alcCaptureStop(ad->device);
alcCaptureCloseDevice(ad->device);
}
return 0;
}
#define OFFSET(x) offsetof(al_data, x)
static const AVOption options[] = {
{"channels", "set number of channels", OFFSET(channels), FF_OPT_TYPE_INT, {.dbl=2}, 1, 2, AV_OPT_FLAG_DECODING_PARAM },
{"sample_rate", "set sample rate", OFFSET(sample_rate), FF_OPT_TYPE_INT, {.dbl=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM },
{"sample_size", "set sample size", OFFSET(sample_size), FF_OPT_TYPE_INT, {.dbl=16}, 8, 16, AV_OPT_FLAG_DECODING_PARAM },
{"list_devices", "list available devices", OFFSET(list_devices), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{"true", "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
{"false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
{NULL},
};
static const AVClass class = {
.class_name = "openal",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT
};
AVInputFormat ff_openal_demuxer = {
.name = "openal",
.long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"),
.priv_data_size = sizeof(al_data),
.read_probe = NULL,
.read_header = read_header,
.read_packet = read_packet,
.read_close = read_close,
.flags = AVFMT_NOFILE,
.priv_class = &class
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment