Browse code

lavdev: add openal input device

Jonathan Baldwin authored on 2011/06/25 15:06:00
Showing 7 changed files
... ...
@@ -1,6 +1,10 @@
1 1
 Entries are sorted chronologically from oldest to youngest within each release,
2 2
 releases are sorted from youngest to oldest.
3 3
 
4
+version next:
5
+
6
+- openal input device added
7
+
4 8
 
5 9
 version 0.8:
6 10
 
... ...
@@ -188,6 +188,7 @@ External library support:
188 188
   --enable-libxavs         enable AVS encoding via xavs [no]
189 189
   --enable-libxvid         enable Xvid encoding via xvidcore,
190 190
                            native MPEG-4/Xvid encoder exists [no]
191
+  --enable-openal          enable OpenAL 1.1 capture support [no]
191 192
   --enable-mlib            enable Sun medialib [no]
192 193
   --enable-zlib            enable zlib [autodetect]
193 194
 
... ...
@@ -959,6 +960,7 @@ CONFIG_LIST="
959 959
     mpegaudiodsp
960 960
     network
961 961
     nonfree
962
+    openal
962 963
     pic
963 964
     postproc
964 965
     rdft
... ...
@@ -1471,6 +1473,7 @@ dv1394_indev_deps="dv1394 dv_demuxer"
1471 1471
 fbdev_indev_deps="linux_fb_h"
1472 1472
 jack_indev_deps="jack_jack_h sem_timedwait"
1473 1473
 libdc1394_indev_deps="libdc1394"
1474
+openal_indev_deps="openal"
1474 1475
 oss_indev_deps_any="soundcard_h sys_soundcard_h"
1475 1476
 oss_outdev_deps_any="soundcard_h sys_soundcard_h"
1476 1477
 sdl_outdev_deps="sdl"
... ...
@@ -2948,6 +2951,11 @@ enabled libx264    && require  libx264 x264.h x264_encoder_encode -lx264 &&
2948 2948
                         die "ERROR: libx264 version must be >= 0.115."; }
2949 2949
 enabled libxavs    && require  libxavs xavs.h xavs_encoder_encode -lxavs
2950 2950
 enabled libxvid    && require  libxvid xvid.h xvid_global -lxvidcore
2951
+enabled openal     && { { for al_libs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
2952
+                        check_lib 'AL/al.h' alGetError "${al_libs}" && break; done } ||
2953
+                        die "ERROR: openal not found"; } &&
2954
+                      { check_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" ||
2955
+                        die "ERROR: openal version must be 1.1 or compatible"; }
2951 2956
 enabled mlib       && require  mediaLib mlib_types.h mlib_VectorSub_S16_U8_Mod -lmlib
2952 2957
 
2953 2958
 SDL_CONFIG="${cross_prefix}sdl-config"
... ...
@@ -3247,6 +3255,7 @@ echo "libvpx enabled            ${libvpx-no}"
3247 3247
 echo "libx264 enabled           ${libx264-no}"
3248 3248
 echo "libxavs enabled           ${libxavs-no}"
3249 3249
 echo "libxvid enabled           ${libxvid-no}"
3250
+echo "openal enabled            ${openal-no}"
3250 3251
 echo "zlib enabled              ${zlib-no}"
3251 3252
 echo "bzlib enabled             ${bzlib-no}"
3252 3253
 echo
... ...
@@ -137,6 +137,95 @@ For more information read:
137 137
 
138 138
 IIDC1394 input device, based on libdc1394 and libraw1394.
139 139
 
140
+@section openal
141
+
142
+The OpenAL input device provides audio capture on all systems with a
143
+working OpenAL 1.1 implementation.
144
+
145
+To enable this input device during configuration, you need OpenAL
146
+headers and libraries installed on your system, and need to configure
147
+FFmpeg with @code{--enable-openal}.
148
+
149
+OpenAL headers and libraries should be provided as part of your OpenAL
150
+implementation, or as an additional download (an SDK). Depending on your
151
+installation you may need to specify additional flags via the
152
+@code{--extra-cflags} and @code{--extra-ldflags} for allowing the build
153
+system to locate the OpenAL headers and libraries.
154
+
155
+An incomplete list of OpenAL implementations follows:
156
+
157
+@table @strong
158
+@item Creative
159
+The official Windows implementation, providing hardware acceleration
160
+with supported devices and software fallback.
161
+See @url{http://openal.org/}.
162
+@item OpenAL Soft
163
+Portable, open source (LGPL) software implementation. Includes
164
+backends for the most common sound APIs on the Windows, Linux,
165
+Solaris, and BSD operating systems.
166
+See @url{http://kcat.strangesoft.net/openal.html}.
167
+@item Apple
168
+OpenAL is part of Core Audio, the official Mac OS X Audio interface.
169
+See @url{http://developer.apple.com/technologies/mac/audio-and-video.html}
170
+@end table
171
+
172
+This device allows to capture from an audio input device handled
173
+through OpenAL.
174
+
175
+You need to specify the name of the device to capture in the provided
176
+filename. If the empty string is provided, the device will
177
+automatically select the default device. You can get the list of the
178
+supported devices by using the option @var{list_devices}.
179
+
180
+@subsection Options
181
+
182
+@table @option
183
+
184
+@item channels
185
+Set the number of channels in the captured audio. Only the values
186
+@option{1} (monaural) and @option{2} (stereo) are currently supported.
187
+Defaults to @option{2}.
188
+
189
+@item sample_size
190
+Set the sample size (in bits) of the captured audio. Only the values
191
+@option{8} and @option{16} are currently supported. Defaults to
192
+@option{16}.
193
+
194
+@item sample_rate
195
+Set the sample rate (in Hz) of the captured audio.
196
+Defaults to @option{44.1k}.
197
+
198
+@item list_devices
199
+If set to @option{true}, print a list of devices and exit.
200
+Defaults to @option{false}.
201
+
202
+@end table
203
+
204
+@subsection Examples
205
+
206
+Print the list of OpenAL supported devices and exit:
207
+@example
208
+$ ffmpeg -list_devices true -f openal -i dummy out.ogg
209
+@end example
210
+
211
+Capture from the OpenAL device @file{DR-BT101 via PulseAudio}:
212
+@example
213
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out.ogg
214
+@end example
215
+
216
+Capture from the default device (note the empty string '' as filename):
217
+@example
218
+$ ffmpeg -f openal -i '' out.ogg
219
+@end example
220
+
221
+Capture from two devices simultaneously, writing to two different files,
222
+within the same @file{ffmpeg} command:
223
+@example
224
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out1.ogg -f openal -i 'ALSA Default' out2.ogg
225
+@end example
226
+Note: not all OpenAL implementations support multiple simultaneous capture -
227
+try the latest OpenAL Soft if the above does not work.
228
+
140 229
 @section oss
141 230
 
142 231
 Open Sound System input device.
... ...
@@ -19,6 +19,7 @@ OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
19 19
 OBJS-$(CONFIG_DV1394_INDEV)              += dv1394.o
20 20
 OBJS-$(CONFIG_FBDEV_INDEV)               += fbdev.o
21 21
 OBJS-$(CONFIG_JACK_INDEV)                += jack_audio.o
22
+OBJS-$(CONFIG_OPENAL_INDEV)              += openal-dec.o
22 23
 OBJS-$(CONFIG_OSS_INDEV)                 += oss_audio.o
23 24
 OBJS-$(CONFIG_OSS_OUTDEV)                += oss_audio.o
24 25
 OBJS-$(CONFIG_SDL_OUTDEV)                += sdl.o
... ...
@@ -44,6 +44,7 @@ void avdevice_register_all(void)
44 44
     REGISTER_INDEV    (DV1394, dv1394);
45 45
     REGISTER_INDEV    (FBDEV, fbdev);
46 46
     REGISTER_INDEV    (JACK, jack);
47
+    REGISTER_INDEV    (OPENAL, openal);
47 48
     REGISTER_INOUTDEV (OSS, oss);
48 49
     REGISTER_OUTDEV   (SDL, sdl);
49 50
     REGISTER_INOUTDEV (SNDIO, sndio);
... ...
@@ -23,8 +23,8 @@
23 23
 #include "libavformat/avformat.h"
24 24
 
25 25
 #define LIBAVDEVICE_VERSION_MAJOR 53
26
-#define LIBAVDEVICE_VERSION_MINOR  1
27
-#define LIBAVDEVICE_VERSION_MICRO  1
26
+#define LIBAVDEVICE_VERSION_MINOR  2
27
+#define LIBAVDEVICE_VERSION_MICRO  0
28 28
 
29 29
 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
30 30
                                                LIBAVDEVICE_VERSION_MINOR, \
31 31
new file mode 100644
... ...
@@ -0,0 +1,256 @@
0
+/*
1
+ * Copyright (c) 2011 Jonathan Baldwin
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in
13
+ * all copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ * THE SOFTWARE.
22
+ */
23
+
24
+/**
25
+ * @file
26
+ * OpenAL 1.1 capture device for libavdevice
27
+ **/
28
+
29
+#include <AL/al.h>
30
+#include <AL/alc.h>
31
+
32
+#include "libavutil/opt.h"
33
+#include "avdevice.h"
34
+
35
+typedef struct {
36
+    AVClass *class;
37
+    /** OpenAL capture device context. **/
38
+    ALCdevice *device;
39
+    /** The number of channels in the captured audio. **/
40
+    int channels;
41
+    /** The sample rate (in Hz) of the captured audio. **/
42
+    int sample_rate;
43
+    /** The sample size (in bits) of the captured audio. **/
44
+    int sample_size;
45
+    /** The OpenAL sample format of the captured audio. **/
46
+    ALCenum sample_format;
47
+    /** The number of bytes between two consecutive samples of the same channel/component. **/
48
+    ALCint sample_step;
49
+    /** If true, print a list of capture devices on this system and exit. **/
50
+    int list_devices;
51
+} al_data;
52
+
53
+typedef struct {
54
+    ALCenum al_fmt;
55
+    enum CodecID codec_id;
56
+    int channels;
57
+} al_format_info;
58
+
59
+#define LOWEST_AL_FORMAT FFMIN(FFMIN(AL_FORMAT_MONO8,AL_FORMAT_MONO16),FFMIN(AL_FORMAT_STEREO8,AL_FORMAT_STEREO16))
60
+
61
+/**
62
+ * Get information about an AL_FORMAT value.
63
+ * @param al_fmt the AL_FORMAT value to find information about.
64
+ * @return A pointer to a structure containing information about the AL_FORMAT value.
65
+ */
66
+static inline al_format_info* get_al_format_info(ALCenum al_fmt)
67
+{
68
+    static al_format_info info_table[] = {
69
+        [AL_FORMAT_MONO8-LOWEST_AL_FORMAT]    = {AL_FORMAT_MONO8, CODEC_ID_PCM_U8, 1},
70
+        [AL_FORMAT_MONO16-LOWEST_AL_FORMAT]   = {AL_FORMAT_MONO16, AV_NE (CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE), 1},
71
+        [AL_FORMAT_STEREO8-LOWEST_AL_FORMAT]  = {AL_FORMAT_STEREO8, CODEC_ID_PCM_U8, 2},
72
+        [AL_FORMAT_STEREO16-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO16, AV_NE (CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE), 2},
73
+    };
74
+
75
+    return &info_table[al_fmt-LOWEST_AL_FORMAT];
76
+}
77
+
78
+/**
79
+ * Get the OpenAL error code, translated into an av/errno error code.
80
+ * @param device The ALC device to check for errors.
81
+ * @param error_msg_ret A pointer to a char* in which to return the error message, or NULL if desired.
82
+ * @return The error code, or 0 if there is no error.
83
+ */
84
+static inline int al_get_error(ALCdevice *device, const char** error_msg_ret)
85
+{
86
+    ALCenum error = alcGetError(device);
87
+    if (error_msg_ret)
88
+        *error_msg_ret = (const char*) alcGetString(device, error);
89
+    switch (error) {
90
+    case ALC_NO_ERROR:
91
+        return 0;
92
+    case ALC_INVALID_DEVICE:
93
+        return AVERROR(ENODEV);
94
+        break;
95
+    case ALC_INVALID_CONTEXT:
96
+    case ALC_INVALID_ENUM:
97
+    case ALC_INVALID_VALUE:
98
+        return AVERROR(EINVAL);
99
+        break;
100
+    case ALC_OUT_OF_MEMORY:
101
+        return AVERROR(ENOMEM);
102
+        break;
103
+    default:
104
+        return AVERROR(EIO);
105
+    }
106
+}
107
+
108
+/**
109
+ * Print out a list of OpenAL capture devices on this system.
110
+ */
111
+static inline void print_al_capture_devices(void *log_ctx)
112
+{
113
+    const char *devices;
114
+
115
+    if (!(devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)))
116
+        return;
117
+
118
+    av_log(log_ctx, AV_LOG_INFO, "List of OpenAL capture devices on this system:\n");
119
+
120
+    for (; *devices != '\0'; devices += strlen(devices) + 1)
121
+        av_log(log_ctx, AV_LOG_INFO, "  %s\n", devices);
122
+}
123
+
124
+static int read_header(AVFormatContext *ctx, AVFormatParameters *ap)
125
+{
126
+    al_data *ad = ctx->priv_data;
127
+    static const ALCenum sample_formats[2][2] = {
128
+        { AL_FORMAT_MONO8,  AL_FORMAT_STEREO8  },
129
+        { AL_FORMAT_MONO16, AL_FORMAT_STEREO16 }
130
+    };
131
+    int error = 0;
132
+    const char *error_msg;
133
+    AVStream *st = NULL;
134
+    AVCodecContext *codec = NULL;
135
+
136
+    if (ad->list_devices) {
137
+        print_al_capture_devices(ctx);
138
+        return AVERROR_EXIT;
139
+    }
140
+
141
+    ad->sample_format = sample_formats[ad->sample_size/8-1][ad->channels-1];
142
+
143
+    /* Open device for capture */
144
+    ad->device =
145
+        alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL,
146
+                             ad->sample_rate,
147
+                             ad->sample_format,
148
+                             ad->sample_rate); /* Maximum 1 second of sample data to be read at once */
149
+
150
+    if (error = al_get_error(ad->device, &error_msg)) goto fail;
151
+
152
+    /* Create stream */
153
+    if (!(st = av_new_stream(ctx, 0))) {
154
+        error = AVERROR(ENOMEM);
155
+        goto fail;
156
+    }
157
+
158
+    /* We work in microseconds */
159
+    av_set_pts_info(st, 64, 1, 1000000);
160
+
161
+    /* Set codec parameters */
162
+    codec = st->codec;
163
+    codec->codec_type = AVMEDIA_TYPE_AUDIO;
164
+    codec->sample_rate = ad->sample_rate;
165
+    codec->channels = get_al_format_info(ad->sample_format)->channels;
166
+    codec->codec_id = get_al_format_info(ad->sample_format)->codec_id;
167
+
168
+    /* This is needed to read the audio data */
169
+    ad->sample_step = (av_get_bits_per_sample(get_al_format_info(ad->sample_format)->codec_id) *
170
+                       get_al_format_info(ad->sample_format)->channels) / 8;
171
+
172
+    /* Finally, start the capture process */
173
+    alcCaptureStart(ad->device);
174
+
175
+    return 0;
176
+
177
+fail:
178
+    /* Handle failure */
179
+    if (ad->device)
180
+        alcCaptureCloseDevice(ad->device);
181
+    if (error_msg)
182
+        av_log(ctx, AV_LOG_ERROR, "Cannot open device: %s\n", error_msg);
183
+    return error;
184
+}
185
+
186
+static int read_packet(AVFormatContext* ctx, AVPacket *pkt)
187
+{
188
+    al_data *ad = ctx->priv_data;
189
+    int error=0;
190
+    const char *error_msg;
191
+    ALCint nb_samples;
192
+
193
+    /* Get number of samples available */
194
+    alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples);
195
+    if (error = al_get_error(ad->device, &error_msg)) goto fail;
196
+
197
+    /* Create a packet of appropriate size */
198
+    av_new_packet(pkt, nb_samples*ad->sample_step);
199
+    pkt->pts = av_gettime();
200
+
201
+    /* Fill the packet with the available samples */
202
+    alcCaptureSamples(ad->device, pkt->data, nb_samples);
203
+    if (error = al_get_error(ad->device, &error_msg)) goto fail;
204
+
205
+    return pkt->size;
206
+fail:
207
+    /* Handle failure */
208
+    if (pkt->data)
209
+        av_destruct_packet(pkt);
210
+    if (error_msg)
211
+        av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg);
212
+    return error;
213
+}
214
+
215
+static int read_close(AVFormatContext* ctx)
216
+{
217
+    al_data *ad = ctx->priv_data;
218
+
219
+    if (ad->device) {
220
+        alcCaptureStop(ad->device);
221
+        alcCaptureCloseDevice(ad->device);
222
+    }
223
+    return 0;
224
+}
225
+
226
+#define OFFSET(x) offsetof(al_data, x)
227
+
228
+static const AVOption options[] = {
229
+    {"channels", "set number of channels",     OFFSET(channels),     FF_OPT_TYPE_INT, {.dbl=2},     1, 2,      AV_OPT_FLAG_DECODING_PARAM },
230
+    {"sample_rate", "set sample rate",         OFFSET(sample_rate),  FF_OPT_TYPE_INT, {.dbl=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM },
231
+    {"sample_size", "set sample size",         OFFSET(sample_size),  FF_OPT_TYPE_INT, {.dbl=16},    8, 16,     AV_OPT_FLAG_DECODING_PARAM },
232
+    {"list_devices", "list available devices", OFFSET(list_devices), FF_OPT_TYPE_INT, {.dbl=0},     0, 1,      AV_OPT_FLAG_DECODING_PARAM },
233
+    {"true",  "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
234
+    {"false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
235
+    {NULL},
236
+};
237
+
238
+static const AVClass class = {
239
+    .class_name = "openal",
240
+    .item_name = av_default_item_name,
241
+    .option = options,
242
+    .version = LIBAVUTIL_VERSION_INT
243
+};
244
+
245
+AVInputFormat ff_openal_demuxer = {
246
+    .name = "openal",
247
+    .long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"),
248
+    .priv_data_size = sizeof(al_data),
249
+    .read_probe = NULL,
250
+    .read_header = read_header,
251
+    .read_packet = read_packet,
252
+    .read_close = read_close,
253
+    .flags = AVFMT_NOFILE,
254
+    .priv_class = &class
255
+};