• 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, AVPacket *pkt)
00301 {
00302     AudioData *s = (AudioData *)s1->priv_data;
00303     int len, ret;
00304     const uint8_t *buf = pkt->data;
00305     int size = pkt->size;
00306 #ifdef LATENCY_CHECK
00307 bigtime_t lat1, lat2;
00308 lat1 = s->player->Latency();
00309 #endif
00310 #ifdef PERF_CHECK
00311     bigtime_t t = s->starve_time;
00312     s->starve_time = 0;
00313     printf("starve_time: %lld    \n", t);
00314 #endif
00315     while (size > 0) {
00316         int amount;
00317         len = MIN(size, AUDIO_BLOCK_SIZE);
00318         if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
00319             return AVERROR(EIO);
00320         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
00321         memcpy(&s->buffer[s->input_index], buf, amount);
00322         s->input_index += amount;
00323         if (s->input_index >= AUDIO_BUFFER_SIZE) {
00324             s->input_index %= AUDIO_BUFFER_SIZE;
00325             memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
00326             s->input_index += len - amount;
00327         }
00328         release_sem_etc(s->output_sem, len, 0);
00329         buf += len;
00330         size -= len;
00331     }
00332 #ifdef LATENCY_CHECK
00333 lat2 = s->player->Latency();
00334 printf("#### BSoundPlayer::Latency(): before= %lld, after= %lld\n", lat1, lat2);
00335 #endif
00336     return 0;
00337 }
00338 
00339 static int audio_write_trailer(AVFormatContext *s1)
00340 {
00341     AudioData *s = (AudioData *)s1->priv_data;
00342 
00343     audio_close(s);
00344     return 0;
00345 }
00346 
00347 /* grab support */
00348 
00349 static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
00350 {
00351     AudioData *s = (AudioData *)s1->priv_data;
00352     AVStream *st;
00353     int ret;
00354 
00355     if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
00356         return -1;
00357 
00358     st = av_new_stream(s1, 0);
00359     if (!st) {
00360         return AVERROR(ENOMEM);
00361     }
00362     s->sample_rate = ap->sample_rate;
00363     s->channels = ap->channels;
00364 
00365     ret = audio_open(s, 0, s1->filename);
00366     if (ret < 0) {
00367         av_free(st);
00368         return AVERROR(EIO);
00369     }
00370     /* take real parameters */
00371     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00372     st->codec->codec_id = s->codec_id;
00373     st->codec->sample_rate = s->sample_rate;
00374     st->codec->channels = s->channels;
00375     return 0;
00376     av_set_pts_info(st, 48, 1, 1000000);  /* 48 bits pts in us */
00377 }
00378 
00379 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
00380 {
00381     AudioData *s = (AudioData *)s1->priv_data;
00382     int size;
00383     size_t len, amount;
00384     unsigned char *buf;
00385     status_t err;
00386 
00387     if (av_new_packet(pkt, s->frame_size) < 0)
00388         return AVERROR(EIO);
00389     buf = (unsigned char *)pkt->data;
00390     size = pkt->size;
00391     while (size > 0) {
00392         len = MIN(AUDIO_BLOCK_SIZE, size);
00393         //printf("acquire_sem(output, %d)\n", len);
00394         while ((err=acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL)) == B_INTERRUPTED);
00395         if (err < B_OK) {
00396             av_free_packet(pkt);
00397             return AVERROR(EIO);
00398         }
00399         amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
00400         memcpy(buf, &s->buffer[s->output_index], amount);
00401         s->output_index += amount;
00402         if (s->output_index >= AUDIO_BUFFER_SIZE) {
00403             s->output_index %= AUDIO_BUFFER_SIZE;
00404             memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
00405             s->output_index += len-amount;
00406             s->output_index %= AUDIO_BUFFER_SIZE;
00407         }
00408         release_sem_etc(s->input_sem, len, 0);
00409         //printf("release_sem(input, %d)\n", len);
00410         buf += len;
00411         size -= len;
00412     }
00413     //XXX: add pts info
00414     return 0;
00415 }
00416 
00417 static int audio_read_close(AVFormatContext *s1)
00418 {
00419     AudioData *s = (AudioData *)s1->priv_data;
00420 
00421     audio_close(s);
00422     return 0;
00423 }
00424 
00425 static AVInputFormat audio_beos_demuxer = {
00426     "audio_beos",
00427     NULL_IF_CONFIG_SMALL("audio grab and output"),
00428     sizeof(AudioData),
00429     NULL,
00430     audio_read_header,
00431     audio_read_packet,
00432     audio_read_close,
00433     NULL,
00434     NULL,
00435     AVFMT_NOFILE,
00436 };
00437 
00438 AVOutputFormat audio_beos_muxer = {
00439     "audio_beos",
00440     NULL_IF_CONFIG_SMALL("audio grab and output"),
00441     "",
00442     "",
00443     sizeof(AudioData),
00444 #if HAVE_BIGENDIAN
00445     CODEC_ID_PCM_S16BE,
00446 #else
00447     CODEC_ID_PCM_S16LE,
00448 #endif
00449     CODEC_ID_NONE,
00450     audio_write_header,
00451     audio_write_packet,
00452     audio_write_trailer,
00453     AVFMT_NOFILE,
00454 };
00455 
00456 extern "C" {
00457 
00458 int audio_init(void)
00459 {
00460     main_thid = find_thread(NULL);
00461     av_register_input_format(&audio_beos_demuxer);
00462     av_register_output_format(&audio_beos_muxer);
00463     return 0;
00464 }
00465 
00466 } // "C"
00467 

Generated on Fri Sep 16 2011 17:17:47 for FFmpeg by  doxygen 1.7.1