• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavdevice/beosaudio.cpp

Go to the documentation of this file.
00001 /*
00002  * BeOS audio play interface
00003  * Copyright (c) 2000, 2001 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include <signal.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <sys/time.h>
00028 
00029 #include <Application.h>
00030 #include <SoundPlayer.h>
00031 
00032 extern "C" {
00033 #include "libavformat/avformat.h"
00034 }
00035 
00036 #if HAVE_BSOUNDRECORDER
00037 #include <SoundRecorder.h>
00038 using namespace BPrivate::Media::Experimental;
00039 #endif
00040 
00041 /* enable performance checks */
00042 //#define PERF_CHECK
00043 
00044 /* enable Media Kit latency checks */
00045 //#define LATENCY_CHECK
00046 
00047 #define AUDIO_BLOCK_SIZE 4096
00048 #define AUDIO_BLOCK_COUNT 8
00049 
00050 #define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT)
00051 
00052 typedef struct {
00053     int fd; // UNUSED
00054     int sample_rate;
00055     int channels;
00056     int frame_size; /* in bytes ! */
00057     CodecID codec_id;
00058     uint8_t buffer[AUDIO_BUFFER_SIZE];
00059     int buffer_ptr;
00060     /* ring buffer */
00061     sem_id input_sem;
00062     int input_index;
00063     sem_id output_sem;
00064     int output_index;
00065     BSoundPlayer *player;
00066 #if HAVE_BSOUNDRECORDER
00067     BSoundRecorder *recorder;
00068 #endif
00069     int has_quit; /* signal callbacks not to wait */
00070     volatile bigtime_t starve_time;
00071 } AudioData;
00072 
00073 static thread_id main_thid;
00074 static thread_id bapp_thid;
00075 static int own_BApp_created = 0;
00076 static int refcount = 0;
00077 
00078 /* create the BApplication and Run() it */
00079 static int32 bapp_thread(void *arg)
00080 {
00081     new BApplication("application/x-vnd.ffmpeg");
00082     own_BApp_created = 1;
00083     be_app->Run();
00084     /* kill the process group */
00085 //    kill(0, SIGINT);
00086 //    kill(main_thid, SIGHUP);
00087     return B_OK;
00088 }
00089 
00090 /* create the BApplication only if needed */
00091 static void create_bapp_if_needed(void)
00092 {
00093     if (refcount++ == 0) {
00094         /* needed by libmedia */
00095         if (be_app == NULL) {
00096             bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL);
00097             resume_thread(bapp_thid);
00098             while (!own_BApp_created)
00099                 snooze(50000);
00100         }
00101     }
00102 }
00103 
00104 static void destroy_bapp_if_needed(void)
00105 {
00106     if (--refcount == 0 && own_BApp_created) {
00107         be_app->Lock();
00108         be_app->Quit();
00109         be_app = NULL;
00110     }
00111 }
00112 
00113 /* called back by BSoundPlayer */
00114 static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format)
00115 {
00116     AudioData *s;
00117     size_t len, amount;
00118     unsigned char *buf = (unsigned char *)buffer;
00119 
00120     s = (AudioData *)cookie;
00121     if (s->has_quit)
00122         return;
00123     while (bufferSize > 0) {
00124 #ifdef PERF_CHECK
00125         bigtime_t t;
00126         t = system_time();
00127 #endif
00128         len = MIN(AUDIO_BLOCK_SIZE, bufferSize);
00129         if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
00130             s->has_quit = 1;
00131             s->player->SetHasData(false);
00132             return;
00133         }
00134         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
00135         memcpy(buf, &s->buffer[s->output_index], amount);
00136         s->output_index += amount;
00137         if (s->output_index >= AUDIO_BUFFER_SIZE) {
00138             s->output_index %= AUDIO_BUFFER_SIZE;
00139             memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
00140             s->output_index += len-amount;
00141             s->output_index %= AUDIO_BUFFER_SIZE;
00142         }
00143         release_sem_etc(s->input_sem, len, 0);
00144 #ifdef PERF_CHECK
00145         t = system_time() - t;
00146         s->starve_time = MAX(s->starve_time, t);
00147 #endif
00148         buf += len;
00149         bufferSize -= len;
00150     }
00151 }
00152 
00153 #if HAVE_BSOUNDRECORDER
00154 /* called back by BSoundRecorder */
00155 static void audiorecord_callback(void *cookie, bigtime_t timestamp, void *buffer, size_t bufferSize, const media_multi_audio_format &format)
00156 {
00157     AudioData *s;
00158     size_t len, amount;
00159     unsigned char *buf = (unsigned char *)buffer;
00160 
00161     s = (AudioData *)cookie;
00162     if (s->has_quit)
00163         return;
00164 
00165     while (bufferSize > 0) {
00166         len = MIN(bufferSize, AUDIO_BLOCK_SIZE);
00167         //printf("acquire_sem(input, %d)\n", len);
00168         if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
00169             s->has_quit = 1;
00170             return;
00171         }
00172         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
00173         memcpy(&s->buffer[s->input_index], buf, amount);
00174         s->input_index += amount;
00175         if (s->input_index >= AUDIO_BUFFER_SIZE) {
00176             s->input_index %= AUDIO_BUFFER_SIZE;
00177             memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
00178             s->input_index += len - amount;
00179         }
00180         release_sem_etc(s->output_sem, len, 0);
00181         //printf("release_sem(output, %d)\n", len);
00182         buf += len;
00183         bufferSize -= len;
00184     }
00185 }
00186 #endif
00187 
00188 static int audio_open(AudioData *s, int is_output, const char *audio_device)
00189 {
00190     int p[2];
00191     int ret;
00192     media_raw_audio_format format;
00193     media_multi_audio_format iformat;
00194 
00195 #if !HAVE_BSOUNDRECORDER
00196     if (!is_output)
00197         return AVERROR(EIO); /* not for now */
00198 #endif
00199     s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input");
00200     if (s->input_sem < B_OK)
00201         return AVERROR(EIO);
00202     s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output");
00203     if (s->output_sem < B_OK) {
00204         delete_sem(s->input_sem);
00205         return AVERROR(EIO);
00206     }
00207     s->input_index = 0;
00208     s->output_index = 0;
00209     create_bapp_if_needed();
00210     s->frame_size = AUDIO_BLOCK_SIZE;
00211     /* bump up the priority (avoid realtime though) */
00212     set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1);
00213 #if HAVE_BSOUNDRECORDER
00214     if (!is_output) {
00215         bool wait_for_input = false;
00216         if (audio_device && !strcmp(audio_device, "wait:"))
00217             wait_for_input = true;
00218         s->recorder = new BSoundRecorder(&iformat, wait_for_input, "ffmpeg input", audiorecord_callback);
00219         if (wait_for_input && (s->recorder->InitCheck() == B_OK)) {
00220             s->recorder->WaitForIncomingConnection(&iformat);
00221         }
00222         if (s->recorder->InitCheck() != B_OK || iformat.format != media_raw_audio_format::B_AUDIO_SHORT) {
00223             delete s->recorder;
00224             s->recorder = NULL;
00225             if (s->input_sem)
00226                 delete_sem(s->input_sem);
00227             if (s->output_sem)
00228                 delete_sem(s->output_sem);
00229             return AVERROR(EIO);
00230         }
00231         s->codec_id = (iformat.byte_order == B_MEDIA_LITTLE_ENDIAN)?CODEC_ID_PCM_S16LE:CODEC_ID_PCM_S16BE;
00232         s->channels = iformat.channel_count;
00233         s->sample_rate = (int)iformat.frame_rate;
00234         s->frame_size = iformat.buffer_size;
00235         s->recorder->SetCookie(s);
00236         s->recorder->SetVolume(1.0);
00237         s->recorder->Start();
00238         return 0;
00239     }
00240 #endif
00241     format = media_raw_audio_format::wildcard;
00242     format.format = media_raw_audio_format::B_AUDIO_SHORT;
00243     format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
00244     format.channel_count = s->channels;
00245     format.buffer_size = s->frame_size;
00246     format.frame_rate = s->sample_rate;
00247     s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback);
00248     if (s->player->InitCheck() != B_OK) {
00249         delete s->player;
00250         s->player = NULL;
00251         if (s->input_sem)
00252             delete_sem(s->input_sem);
00253         if (s->output_sem)
00254             delete_sem(s->output_sem);
00255         return AVERROR(EIO);
00256     }
00257     s->player->SetCookie(s);
00258     s->player->SetVolume(1.0);
00259     s->player->Start();
00260     s->player->SetHasData(true);
00261     return 0;
00262 }
00263 
00264 static int audio_close(AudioData *s)
00265 {
00266     if (s->input_sem)
00267         delete_sem(s->input_sem);
00268     if (s->output_sem)
00269         delete_sem(s->output_sem);
00270     s->has_quit = 1;
00271     if (s->player) {
00272         s->player->Stop();
00273     }
00274     if (s->player)
00275         delete s->player;
00276 #if HAVE_BSOUNDRECORDER
00277     if (s->recorder)
00278         delete s->recorder;
00279 #endif
00280     destroy_bapp_if_needed();
00281     return 0;
00282 }
00283 
00284 /* sound output support */
00285 static int audio_write_header(AVFormatContext *s1)
00286 {
00287     AudioData *s = (AudioData *)s1->priv_data;
00288     AVStream *st;
00289     int ret;
00290 
00291     st = s1->streams[0];
00292     s->sample_rate = st->codec->sample_rate;
00293     s->channels = st->codec->channels;
00294     ret = audio_open(s, 1, NULL);
00295     if (ret < 0)
00296         return AVERROR(EIO);
00297     return 0;
00298 }
00299 
00300 static int audio_write_packet(AVFormatContext *s1, int stream_index,
00301                               const uint8_t *buf, int size, int64_t force_pts)
00302 {
00303     AudioData *s = (AudioData *)s1->priv_data;
00304     int len, ret;
00305 #ifdef LATENCY_CHECK
00306 bigtime_t lat1, lat2;
00307 lat1 = s->player->Latency();
00308 #endif
00309 #ifdef PERF_CHECK
00310     bigtime_t t = s->starve_time;
00311     s->starve_time = 0;
00312     printf("starve_time: %lld    \n", t);
00313 #endif
00314     while (size > 0) {
00315         int amount;
00316         len = MIN(size, AUDIO_BLOCK_SIZE);
00317         if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
00318             return AVERROR(EIO);
00319         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
00320         memcpy(&s->buffer[s->input_index], buf, amount);
00321         s->input_index += amount;
00322         if (s->input_index >= AUDIO_BUFFER_SIZE) {
00323             s->input_index %= AUDIO_BUFFER_SIZE;
00324             memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
00325             s->input_index += len - amount;
00326         }
00327         release_sem_etc(s->output_sem, len, 0);
00328         buf += len;
00329         size -= len;
00330     }
00331 #ifdef LATENCY_CHECK
00332 lat2 = s->player->Latency();
00333 printf("#### BSoundPlayer::Latency(): before= %lld, after= %lld\n", lat1, lat2);
00334 #endif
00335     return 0;
00336 }
00337 
00338 static int audio_write_trailer(AVFormatContext *s1)
00339 {
00340     AudioData *s = (AudioData *)s1->priv_data;
00341 
00342     audio_close(s);
00343     return 0;
00344 }
00345 
00346 /* grab support */
00347 
00348 static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
00349 {
00350     AudioData *s = (AudioData *)s1->priv_data;
00351     AVStream *st;
00352     int ret;
00353 
00354     if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
00355         return -1;
00356 
00357     st = av_new_stream(s1, 0);
00358     if (!st) {
00359         return AVERROR(ENOMEM);
00360     }
00361     s->sample_rate = ap->sample_rate;
00362     s->channels = ap->channels;
00363 
00364     ret = audio_open(s, 0, s1->filename);
00365     if (ret < 0) {
00366         av_free(st);
00367         return AVERROR(EIO);
00368     }
00369     /* take real parameters */
00370     st->codec->codec_type = CODEC_TYPE_AUDIO;
00371     st->codec->codec_id = s->codec_id;
00372     st->codec->sample_rate = s->sample_rate;
00373     st->codec->channels = s->channels;
00374     return 0;
00375     av_set_pts_info(s1, 48, 1, 1000000);  /* 48 bits pts in us */
00376 }
00377 
00378 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
00379 {
00380     AudioData *s = (AudioData *)s1->priv_data;
00381     int size;
00382     size_t len, amount;
00383     unsigned char *buf;
00384     status_t err;
00385 
00386     if (av_new_packet(pkt, s->frame_size) < 0)
00387         return AVERROR(EIO);
00388     buf = (unsigned char *)pkt->data;
00389     size = pkt->size;
00390     while (size > 0) {
00391         len = MIN(AUDIO_BLOCK_SIZE, size);
00392         //printf("acquire_sem(output, %d)\n", len);
00393         while ((err=acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL)) == B_INTERRUPTED);
00394         if (err < B_OK) {
00395             av_free_packet(pkt);
00396             return AVERROR(EIO);
00397         }
00398         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
00399         memcpy(buf, &s->buffer[s->output_index], amount);
00400         s->output_index += amount;
00401         if (s->output_index >= AUDIO_BUFFER_SIZE) {
00402             s->output_index %= AUDIO_BUFFER_SIZE;
00403             memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
00404             s->output_index += len-amount;
00405             s->output_index %= AUDIO_BUFFER_SIZE;
00406         }
00407         release_sem_etc(s->input_sem, len, 0);
00408         //printf("release_sem(input, %d)\n", len);
00409         buf += len;
00410         size -= len;
00411     }
00412     //XXX: add pts info
00413     return 0;
00414 }
00415 
00416 static int audio_read_close(AVFormatContext *s1)
00417 {
00418     AudioData *s = (AudioData *)s1->priv_data;
00419 
00420     audio_close(s);
00421     return 0;
00422 }
00423 
00424 static AVInputFormat audio_beos_demuxer = {
00425     "audio_beos",
00426     NULL_IF_CONFIG_SMALL("audio grab and output"),
00427     sizeof(AudioData),
00428     NULL,
00429     audio_read_header,
00430     audio_read_packet,
00431     audio_read_close,
00432     NULL,
00433     AVFMT_NOFILE,
00434 };
00435 
00436 AVOutputFormat audio_beos_muxer = {
00437     "audio_beos",
00438     NULL_IF_CONFIG_SMALL("audio grab and output"),
00439     "",
00440     "",
00441     sizeof(AudioData),
00442 #ifdef WORDS_BIGENDIAN
00443     CODEC_ID_PCM_S16BE,
00444 #else
00445     CODEC_ID_PCM_S16LE,
00446 #endif
00447     CODEC_ID_NONE,
00448     audio_write_header,
00449     audio_write_packet,
00450     audio_write_trailer,
00451     AVFMT_NOFILE,
00452 };
00453 
00454 extern "C" {
00455 
00456 int audio_init(void)
00457 {
00458     main_thid = find_thread(NULL);
00459     av_register_input_format(&audio_beos_demuxer);
00460     av_register_output_format(&audio_beos_muxer);
00461     return 0;
00462 }
00463 
00464 } // "C"
00465 

Generated on Sat Feb 16 2013 09:23:14 for ffmpeg by  doxygen 1.7.1