00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00042
00043
00044
00045
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;
00054 int sample_rate;
00055 int channels;
00056 int frame_size;
00057 CodecID codec_id;
00058 uint8_t buffer[AUDIO_BUFFER_SIZE];
00059 int buffer_ptr;
00060
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;
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
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
00085
00086
00087 return B_OK;
00088 }
00089
00090
00091 static void create_bapp_if_needed(void)
00092 {
00093 if (refcount++ == 0) {
00094
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
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
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
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
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);
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
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
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
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
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);
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
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
00410 buf += len;
00411 size -= len;
00412 }
00413
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 }
00467