Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2011 Jonathan Baldwin
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * Permission to use, copy, modify, and/or distribute this software for any
  7.  * purpose with or without fee is hereby granted, provided that the above
  8.  * copyright notice and this permission notice appear in all copies.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  11.  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  12.  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  13.  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  14.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  15.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  16.  * PERFORMANCE OF THIS SOFTWARE.
  17.  */
  18.  
  19. /**
  20.  * @file
  21.  * OpenAL 1.1 capture device for libavdevice
  22.  **/
  23.  
  24. #include <AL/al.h>
  25. #include <AL/alc.h>
  26.  
  27. #include "libavutil/opt.h"
  28. #include "libavutil/time.h"
  29. #include "libavformat/internal.h"
  30. #include "avdevice.h"
  31.  
  32. typedef struct {
  33.     AVClass *class;
  34.     /** OpenAL capture device context. **/
  35.     ALCdevice *device;
  36.     /** The number of channels in the captured audio. **/
  37.     int channels;
  38.     /** The sample rate (in Hz) of the captured audio. **/
  39.     int sample_rate;
  40.     /** The sample size (in bits) of the captured audio. **/
  41.     int sample_size;
  42.     /** The OpenAL sample format of the captured audio. **/
  43.     ALCenum sample_format;
  44.     /** The number of bytes between two consecutive samples of the same channel/component. **/
  45.     ALCint sample_step;
  46.     /** If true, print a list of capture devices on this system and exit. **/
  47.     int list_devices;
  48. } al_data;
  49.  
  50. typedef struct {
  51.     ALCenum al_fmt;
  52.     enum AVCodecID codec_id;
  53.     int channels;
  54. } al_format_info;
  55.  
  56. #define LOWEST_AL_FORMAT FFMIN(FFMIN(AL_FORMAT_MONO8,AL_FORMAT_MONO16),FFMIN(AL_FORMAT_STEREO8,AL_FORMAT_STEREO16))
  57.  
  58. /**
  59.  * Get information about an AL_FORMAT value.
  60.  * @param al_fmt the AL_FORMAT value to find information about.
  61.  * @return A pointer to a structure containing information about the AL_FORMAT value.
  62.  */
  63. static inline al_format_info* get_al_format_info(ALCenum al_fmt)
  64. {
  65.     static al_format_info info_table[] = {
  66.         [AL_FORMAT_MONO8-LOWEST_AL_FORMAT]    = {AL_FORMAT_MONO8, AV_CODEC_ID_PCM_U8, 1},
  67.         [AL_FORMAT_MONO16-LOWEST_AL_FORMAT]   = {AL_FORMAT_MONO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 1},
  68.         [AL_FORMAT_STEREO8-LOWEST_AL_FORMAT]  = {AL_FORMAT_STEREO8, AV_CODEC_ID_PCM_U8, 2},
  69.         [AL_FORMAT_STEREO16-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 2},
  70.     };
  71.  
  72.     return &info_table[al_fmt-LOWEST_AL_FORMAT];
  73. }
  74.  
  75. /**
  76.  * Get the OpenAL error code, translated into an av/errno error code.
  77.  * @param device The ALC device to check for errors.
  78.  * @param error_msg_ret A pointer to a char* in which to return the error message, or NULL if desired.
  79.  * @return The error code, or 0 if there is no error.
  80.  */
  81. static inline int al_get_error(ALCdevice *device, const char** error_msg_ret)
  82. {
  83.     ALCenum error = alcGetError(device);
  84.     if (error_msg_ret)
  85.         *error_msg_ret = (const char*) alcGetString(device, error);
  86.     switch (error) {
  87.     case ALC_NO_ERROR:
  88.         return 0;
  89.     case ALC_INVALID_DEVICE:
  90.         return AVERROR(ENODEV);
  91.         break;
  92.     case ALC_INVALID_CONTEXT:
  93.     case ALC_INVALID_ENUM:
  94.     case ALC_INVALID_VALUE:
  95.         return AVERROR(EINVAL);
  96.         break;
  97.     case ALC_OUT_OF_MEMORY:
  98.         return AVERROR(ENOMEM);
  99.         break;
  100.     default:
  101.         return AVERROR(EIO);
  102.     }
  103. }
  104.  
  105. /**
  106.  * Print out a list of OpenAL capture devices on this system.
  107.  */
  108. static inline void print_al_capture_devices(void *log_ctx)
  109. {
  110.     const char *devices;
  111.  
  112.     if (!(devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)))
  113.         return;
  114.  
  115.     av_log(log_ctx, AV_LOG_INFO, "List of OpenAL capture devices on this system:\n");
  116.  
  117.     for (; *devices != '\0'; devices += strlen(devices) + 1)
  118.         av_log(log_ctx, AV_LOG_INFO, "  %s\n", devices);
  119. }
  120.  
  121. static int read_header(AVFormatContext *ctx)
  122. {
  123.     al_data *ad = ctx->priv_data;
  124.     static const ALCenum sample_formats[2][2] = {
  125.         { AL_FORMAT_MONO8,  AL_FORMAT_STEREO8  },
  126.         { AL_FORMAT_MONO16, AL_FORMAT_STEREO16 }
  127.     };
  128.     int error = 0;
  129.     const char *error_msg;
  130.     AVStream *st = NULL;
  131.     AVCodecContext *codec = NULL;
  132.  
  133.     if (ad->list_devices) {
  134.         print_al_capture_devices(ctx);
  135.         return AVERROR_EXIT;
  136.     }
  137.  
  138.     ad->sample_format = sample_formats[ad->sample_size/8-1][ad->channels-1];
  139.  
  140.     /* Open device for capture */
  141.     ad->device =
  142.         alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL,
  143.                              ad->sample_rate,
  144.                              ad->sample_format,
  145.                              ad->sample_rate); /* Maximum 1 second of sample data to be read at once */
  146.  
  147.     if (error = al_get_error(ad->device, &error_msg)) goto fail;
  148.  
  149.     /* Create stream */
  150.     if (!(st = avformat_new_stream(ctx, NULL))) {
  151.         error = AVERROR(ENOMEM);
  152.         goto fail;
  153.     }
  154.  
  155.     /* We work in microseconds */
  156.     avpriv_set_pts_info(st, 64, 1, 1000000);
  157.  
  158.     /* Set codec parameters */
  159.     codec = st->codec;
  160.     codec->codec_type = AVMEDIA_TYPE_AUDIO;
  161.     codec->sample_rate = ad->sample_rate;
  162.     codec->channels = get_al_format_info(ad->sample_format)->channels;
  163.     codec->codec_id = get_al_format_info(ad->sample_format)->codec_id;
  164.  
  165.     /* This is needed to read the audio data */
  166.     ad->sample_step = (av_get_bits_per_sample(get_al_format_info(ad->sample_format)->codec_id) *
  167.                        get_al_format_info(ad->sample_format)->channels) / 8;
  168.  
  169.     /* Finally, start the capture process */
  170.     alcCaptureStart(ad->device);
  171.  
  172.     return 0;
  173.  
  174. fail:
  175.     /* Handle failure */
  176.     if (ad->device)
  177.         alcCaptureCloseDevice(ad->device);
  178.     if (error_msg)
  179.         av_log(ctx, AV_LOG_ERROR, "Cannot open device: %s\n", error_msg);
  180.     return error;
  181. }
  182.  
  183. static int read_packet(AVFormatContext* ctx, AVPacket *pkt)
  184. {
  185.     al_data *ad = ctx->priv_data;
  186.     int error=0;
  187.     const char *error_msg;
  188.     ALCint nb_samples;
  189.  
  190.     /* Get number of samples available */
  191.     alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples);
  192.     if (error = al_get_error(ad->device, &error_msg)) goto fail;
  193.  
  194.     /* Create a packet of appropriate size */
  195.     av_new_packet(pkt, nb_samples*ad->sample_step);
  196.     pkt->pts = av_gettime();
  197.  
  198.     /* Fill the packet with the available samples */
  199.     alcCaptureSamples(ad->device, pkt->data, nb_samples);
  200.     if (error = al_get_error(ad->device, &error_msg)) goto fail;
  201.  
  202.     return pkt->size;
  203. fail:
  204.     /* Handle failure */
  205.     if (pkt->data)
  206.         av_destruct_packet(pkt);
  207.     if (error_msg)
  208.         av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg);
  209.     return error;
  210. }
  211.  
  212. static int read_close(AVFormatContext* ctx)
  213. {
  214.     al_data *ad = ctx->priv_data;
  215.  
  216.     if (ad->device) {
  217.         alcCaptureStop(ad->device);
  218.         alcCaptureCloseDevice(ad->device);
  219.     }
  220.     return 0;
  221. }
  222.  
  223. #define OFFSET(x) offsetof(al_data, x)
  224.  
  225. static const AVOption options[] = {
  226.     {"channels", "set number of channels",     OFFSET(channels),     AV_OPT_TYPE_INT, {.i64=2},     1, 2,      AV_OPT_FLAG_DECODING_PARAM },
  227.     {"sample_rate", "set sample rate",         OFFSET(sample_rate),  AV_OPT_TYPE_INT, {.i64=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM },
  228.     {"sample_size", "set sample size",         OFFSET(sample_size),  AV_OPT_TYPE_INT, {.i64=16},    8, 16,     AV_OPT_FLAG_DECODING_PARAM },
  229.     {"list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0},     0, 1,      AV_OPT_FLAG_DECODING_PARAM, "list_devices"  },
  230.     {"true",  "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
  231.     {"false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
  232.     {NULL},
  233. };
  234.  
  235. static const AVClass class = {
  236.     .class_name = "openal",
  237.     .item_name = av_default_item_name,
  238.     .option = options,
  239.     .version = LIBAVUTIL_VERSION_INT
  240. };
  241.  
  242. AVInputFormat ff_openal_demuxer = {
  243.     .name = "openal",
  244.     .long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"),
  245.     .priv_data_size = sizeof(al_data),
  246.     .read_probe = NULL,
  247.     .read_header = read_header,
  248.     .read_packet = read_packet,
  249.     .read_close = read_close,
  250.     .flags = AVFMT_NOFILE,
  251.     .priv_class = &class
  252. };
  253.