diff options
author | Jonathan Baldwin <jbaldwin9182@gmail.com> | 2011-06-25 08:06:00 +0200 |
---|---|---|
committer | Stefano Sabatini <stefano.sabatini-lala@poste.it> | 2011-06-27 15:26:14 +0200 |
commit | 65eae2a7a2a14926c9f9683544e99982ba565f93 (patch) | |
tree | 6211f5038dad15d1a99bbd8cdc1e2bba678d23e3 | |
parent | cdeb803e2fe1239e0217186c7441c94adb0d9895 (diff) | |
download | ffmpeg-65eae2a7a2a14926c9f9683544e99982ba565f93.tar.gz |
lavdev: add openal input device
-rw-r--r-- | Changelog | 4 | ||||
-rwxr-xr-x | configure | 9 | ||||
-rw-r--r-- | doc/indevs.texi | 89 | ||||
-rw-r--r-- | libavdevice/Makefile | 1 | ||||
-rw-r--r-- | libavdevice/alldevices.c | 1 | ||||
-rw-r--r-- | libavdevice/avdevice.h | 4 | ||||
-rw-r--r-- | libavdevice/openal-dec.c | 256 |
7 files changed, 362 insertions, 2 deletions
@@ -1,6 +1,10 @@ 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 diff --git a/doc/indevs.texi b/doc/indevs.texi index 04871081dd..6d837ed412 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -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. diff --git a/libavdevice/Makefile b/libavdevice/Makefile index 60103a4864..4d3c1aec6c 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -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 diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index 7846704861..ef302d700d 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -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); diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h index e49e5b71f7..7cb8f5497f 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -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, \ diff --git a/libavdevice/openal-dec.c b/libavdevice/openal-dec.c new file mode 100644 index 0000000000..f01dff7d87 --- /dev/null +++ b/libavdevice/openal-dec.c @@ -0,0 +1,256 @@ +/* + * 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 +}; |