diff options
Diffstat (limited to 'src/plugins/ffmpeg/libavdevice/beosaudio.cpp')
-rw-r--r-- | src/plugins/ffmpeg/libavdevice/beosaudio.cpp | 465 |
1 files changed, 0 insertions, 465 deletions
diff --git a/src/plugins/ffmpeg/libavdevice/beosaudio.cpp b/src/plugins/ffmpeg/libavdevice/beosaudio.cpp deleted file mode 100644 index def1fad..0000000 --- a/src/plugins/ffmpeg/libavdevice/beosaudio.cpp +++ /dev/null | |||
@@ -1,465 +0,0 @@ | |||
1 | /* | ||
2 | * BeOS audio play interface | ||
3 | * Copyright (c) 2000, 2001 Fabrice Bellard. | ||
4 | * | ||
5 | * This file is part of FFmpeg. | ||
6 | * | ||
7 | * FFmpeg is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU Lesser General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2.1 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * FFmpeg is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | ||
18 | * License along with FFmpeg; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | #include <signal.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <string.h> | ||
26 | #include <unistd.h> | ||
27 | #include <sys/time.h> | ||
28 | |||
29 | #include <Application.h> | ||
30 | #include <SoundPlayer.h> | ||
31 | |||
32 | extern "C" { | ||
33 | #include "libavformat/avformat.h" | ||
34 | } | ||
35 | |||
36 | #ifdef HAVE_BSOUNDRECORDER | ||
37 | #include <SoundRecorder.h> | ||
38 | using namespace BPrivate::Media::Experimental; | ||
39 | #endif | ||
40 | |||
41 | /* enable performance checks */ | ||
42 | //#define PERF_CHECK | ||
43 | |||
44 | /* enable Media Kit latency checks */ | ||
45 | //#define LATENCY_CHECK | ||
46 | |||
47 | #define AUDIO_BLOCK_SIZE 4096 | ||
48 | #define AUDIO_BLOCK_COUNT 8 | ||
49 | |||
50 | #define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT) | ||
51 | |||
52 | typedef struct { | ||
53 | int fd; // UNUSED | ||
54 | int sample_rate; | ||
55 | int channels; | ||
56 | int frame_size; /* in bytes ! */ | ||
57 | CodecID codec_id; | ||
58 | uint8_t buffer[AUDIO_BUFFER_SIZE]; | ||
59 | int buffer_ptr; | ||
60 | /* ring buffer */ | ||
61 | sem_id input_sem; | ||
62 | int input_index; | ||
63 | sem_id output_sem; | ||
64 | int output_index; | ||
65 | BSoundPlayer *player; | ||
66 | #ifdef HAVE_BSOUNDRECORDER | ||
67 | BSoundRecorder *recorder; | ||
68 | #endif | ||
69 | int has_quit; /* signal callbacks not to wait */ | ||
70 | volatile bigtime_t starve_time; | ||
71 | } AudioData; | ||
72 | |||
73 | static thread_id main_thid; | ||
74 | static thread_id bapp_thid; | ||
75 | static int own_BApp_created = 0; | ||
76 | static int refcount = 0; | ||
77 | |||
78 | /* create the BApplication and Run() it */ | ||
79 | static int32 bapp_thread(void *arg) | ||
80 | { | ||
81 | new BApplication("application/x-vnd.ffmpeg"); | ||
82 | own_BApp_created = 1; | ||
83 | be_app->Run(); | ||
84 | /* kill the process group */ | ||
85 | // kill(0, SIGINT); | ||
86 | // kill(main_thid, SIGHUP); | ||
87 | return B_OK; | ||
88 | } | ||
89 | |||
90 | /* create the BApplication only if needed */ | ||
91 | static void create_bapp_if_needed(void) | ||
92 | { | ||
93 | if (refcount++ == 0) { | ||
94 | /* needed by libmedia */ | ||
95 | if (be_app == NULL) { | ||
96 | bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL); | ||
97 | resume_thread(bapp_thid); | ||
98 | while (!own_BApp_created) | ||
99 | snooze(50000); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static void destroy_bapp_if_needed(void) | ||
105 | { | ||
106 | if (--refcount == 0 && own_BApp_created) { | ||
107 | be_app->Lock(); | ||
108 | be_app->Quit(); | ||
109 | be_app = NULL; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | /* called back by BSoundPlayer */ | ||
114 | static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format) | ||
115 | { | ||
116 | AudioData *s; | ||
117 | size_t len, amount; | ||
118 | unsigned char *buf = (unsigned char *)buffer; | ||
119 | |||
120 | s = (AudioData *)cookie; | ||
121 | if (s->has_quit) | ||
122 | return; | ||
123 | while (bufferSize > 0) { | ||
124 | #ifdef PERF_CHECK | ||
125 | bigtime_t t; | ||
126 | t = system_time(); | ||
127 | #endif | ||
128 | len = MIN(AUDIO_BLOCK_SIZE, bufferSize); | ||
129 | if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) { | ||
130 | s->has_quit = 1; | ||
131 | s->player->SetHasData(false); | ||
132 | return; | ||
133 | } | ||
134 | amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index)); | ||
135 | memcpy(buf, &s->buffer[s->output_index], amount); | ||
136 | s->output_index += amount; | ||
137 | if (s->output_index >= AUDIO_BUFFER_SIZE) { | ||
138 | s->output_index %= AUDIO_BUFFER_SIZE; | ||
139 | memcpy(buf + amount, &s->buffer[s->output_index], len - amount); | ||
140 | s->output_index += len-amount; | ||
141 | s->output_index %= AUDIO_BUFFER_SIZE; | ||
142 | } | ||
143 | release_sem_etc(s->input_sem, len, 0); | ||
144 | #ifdef PERF_CHECK | ||
145 | t = system_time() - t; | ||
146 | s->starve_time = MAX(s->starve_time, t); | ||
147 | #endif | ||
148 | buf += len; | ||
149 | bufferSize -= len; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | #ifdef HAVE_BSOUNDRECORDER | ||
154 | /* called back by BSoundRecorder */ | ||
155 | static void audiorecord_callback(void *cookie, bigtime_t timestamp, void *buffer, size_t bufferSize, const media_multi_audio_format &format) | ||
156 | { | ||
157 | AudioData *s; | ||
158 | size_t len, amount; | ||
159 | unsigned char *buf = (unsigned char *)buffer; | ||
160 | |||
161 | s = (AudioData *)cookie; | ||
162 | if (s->has_quit) | ||
163 | return; | ||
164 | |||
165 | while (bufferSize > 0) { | ||
166 | len = MIN(bufferSize, AUDIO_BLOCK_SIZE); | ||
167 | //printf("acquire_sem(input, %d)\n", len); | ||
168 | if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) { | ||
169 | s->has_quit = 1; | ||
170 | return; | ||
171 | } | ||
172 | amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index)); | ||
173 | memcpy(&s->buffer[s->input_index], buf, amount); | ||
174 | s->input_index += amount; | ||
175 | if (s->input_index >= AUDIO_BUFFER_SIZE) { | ||
176 | s->input_index %= AUDIO_BUFFER_SIZE; | ||
177 | memcpy(&s->buffer[s->input_index], buf + amount, len - amount); | ||
178 | s->input_index += len - amount; | ||
179 | } | ||
180 | release_sem_etc(s->output_sem, len, 0); | ||
181 | //printf("release_sem(output, %d)\n", len); | ||
182 | buf += len; | ||
183 | bufferSize -= len; | ||
184 | } | ||
185 | } | ||
186 | #endif | ||
187 | |||
188 | static int audio_open(AudioData *s, int is_output, const char *audio_device) | ||
189 | { | ||
190 | int p[2]; | ||
191 | int ret; | ||
192 | media_raw_audio_format format; | ||
193 | media_multi_audio_format iformat; | ||
194 | |||
195 | #ifndef HAVE_BSOUNDRECORDER | ||
196 | if (!is_output) | ||
197 | return AVERROR(EIO); /* not for now */ | ||
198 | #endif | ||
199 | s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input"); | ||
200 | if (s->input_sem < B_OK) | ||
201 | return AVERROR(EIO); | ||
202 | s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output"); | ||
203 | if (s->output_sem < B_OK) { | ||
204 | delete_sem(s->input_sem); | ||
205 | return AVERROR(EIO); | ||
206 | } | ||
207 | s->input_index = 0; | ||
208 | s->output_index = 0; | ||
209 | create_bapp_if_needed(); | ||
210 | s->frame_size = AUDIO_BLOCK_SIZE; | ||
211 | /* bump up the priority (avoid realtime though) */ | ||
212 | set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1); | ||
213 | #ifdef HAVE_BSOUNDRECORDER | ||
214 | if (!is_output) { | ||
215 | bool wait_for_input = false; | ||
216 | if (audio_device && !strcmp(audio_device, "wait:")) | ||
217 | wait_for_input = true; | ||
218 | s->recorder = new BSoundRecorder(&iformat, wait_for_input, "ffmpeg input", audiorecord_callback); | ||
219 | if (wait_for_input && (s->recorder->InitCheck() == B_OK)) { | ||
220 | s->recorder->WaitForIncomingConnection(&iformat); | ||
221 | } | ||
222 | if (s->recorder->InitCheck() != B_OK || iformat.format != media_raw_audio_format::B_AUDIO_SHORT) { | ||
223 | delete s->recorder; | ||
224 | s->recorder = NULL; | ||
225 | if (s->input_sem) | ||
226 | delete_sem(s->input_sem); | ||
227 | if (s->output_sem) | ||
228 | delete_sem(s->output_sem); | ||
229 | return AVERROR(EIO); | ||
230 | } | ||
231 | s->codec_id = (iformat.byte_order == B_MEDIA_LITTLE_ENDIAN)?CODEC_ID_PCM_S16LE:CODEC_ID_PCM_S16BE; | ||
232 | s->channels = iformat.channel_count; | ||
233 | s->sample_rate = (int)iformat.frame_rate; | ||
234 | s->frame_size = iformat.buffer_size; | ||
235 | s->recorder->SetCookie(s); | ||
236 | s->recorder->SetVolume(1.0); | ||
237 | s->recorder->Start(); | ||
238 | return 0; | ||
239 | } | ||
240 | #endif | ||
241 | format = media_raw_audio_format::wildcard; | ||
242 | format.format = media_raw_audio_format::B_AUDIO_SHORT; | ||
243 | format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN; | ||
244 | format.channel_count = s->channels; | ||
245 | format.buffer_size = s->frame_size; | ||
246 | format.frame_rate = s->sample_rate; | ||
247 | s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback); | ||
248 | if (s->player->InitCheck() != B_OK) { | ||
249 | delete s->player; | ||
250 | s->player = NULL; | ||
251 | if (s->input_sem) | ||
252 | delete_sem(s->input_sem); | ||
253 | if (s->output_sem) | ||
254 | delete_sem(s->output_sem); | ||
255 | return AVERROR(EIO); | ||
256 | } | ||
257 | s->player->SetCookie(s); | ||
258 | s->player->SetVolume(1.0); | ||
259 | s->player->Start(); | ||
260 | s->player->SetHasData(true); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int audio_close(AudioData *s) | ||
265 | { | ||
266 | if (s->input_sem) | ||
267 | delete_sem(s->input_sem); | ||
268 | if (s->output_sem) | ||
269 | delete_sem(s->output_sem); | ||
270 | s->has_quit = 1; | ||
271 | if (s->player) { | ||
272 | s->player->Stop(); | ||
273 | } | ||
274 | if (s->player) | ||
275 | delete s->player; | ||
276 | #ifdef HAVE_BSOUNDRECORDER | ||
277 | if (s->recorder) | ||
278 | delete s->recorder; | ||
279 | #endif | ||
280 | destroy_bapp_if_needed(); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* sound output support */ | ||
285 | static int audio_write_header(AVFormatContext *s1) | ||
286 | { | ||
287 | AudioData *s = (AudioData *)s1->priv_data; | ||
288 | AVStream *st; | ||
289 | int ret; | ||
290 | |||
291 | st = s1->streams[0]; | ||
292 | s->sample_rate = st->codec->sample_rate; | ||
293 | s->channels = st->codec->channels; | ||
294 | ret = audio_open(s, 1, NULL); | ||
295 | if (ret < 0) | ||
296 | return AVERROR(EIO); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int audio_write_packet(AVFormatContext *s1, int stream_index, | ||
301 | const uint8_t *buf, int size, int64_t force_pts) | ||
302 | { | ||
303 | AudioData *s = (AudioData *)s1->priv_data; | ||
304 | int len, ret; | ||
305 | #ifdef LATENCY_CHECK | ||
306 | bigtime_t lat1, lat2; | ||
307 | lat1 = s->player->Latency(); | ||
308 | #endif | ||
309 | #ifdef PERF_CHECK | ||
310 | bigtime_t t = s->starve_time; | ||
311 | s->starve_time = 0; | ||
312 | printf("starve_time: %lld \n", t); | ||
313 | #endif | ||
314 | while (size > 0) { | ||
315 | int amount; | ||
316 | len = MIN(size, AUDIO_BLOCK_SIZE); | ||
317 | if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) | ||
318 | return AVERROR(EIO); | ||
319 | amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index)); | ||
320 | memcpy(&s->buffer[s->input_index], buf, amount); | ||
321 | s->input_index += amount; | ||
322 | if (s->input_index >= AUDIO_BUFFER_SIZE) { | ||
323 | s->input_index %= AUDIO_BUFFER_SIZE; | ||
324 | memcpy(&s->buffer[s->input_index], buf + amount, len - amount); | ||
325 | s->input_index += len - amount; | ||
326 | } | ||
327 | release_sem_etc(s->output_sem, len, 0); | ||
328 | buf += len; | ||
329 | size -= len; | ||
330 | } | ||
331 | #ifdef LATENCY_CHECK | ||
332 | lat2 = s->player->Latency(); | ||
333 | printf("#### BSoundPlayer::Latency(): before= %lld, after= %lld\n", lat1, lat2); | ||
334 | #endif | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int audio_write_trailer(AVFormatContext *s1) | ||
339 | { | ||
340 | AudioData *s = (AudioData *)s1->priv_data; | ||
341 | |||
342 | audio_close(s); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | /* grab support */ | ||
347 | |||
348 | static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap) | ||
349 | { | ||
350 | AudioData *s = (AudioData *)s1->priv_data; | ||
351 | AVStream *st; | ||
352 | int ret; | ||
353 | |||
354 | if (!ap || ap->sample_rate <= 0 || ap->channels <= 0) | ||
355 | return -1; | ||
356 | |||
357 | st = av_new_stream(s1, 0); | ||
358 | if (!st) { | ||
359 | return AVERROR(ENOMEM); | ||
360 | } | ||
361 | s->sample_rate = ap->sample_rate; | ||
362 | s->channels = ap->channels; | ||
363 | |||
364 | ret = audio_open(s, 0, s1->filename); | ||
365 | if (ret < 0) { | ||
366 | av_free(st); | ||
367 | return AVERROR(EIO); | ||
368 | } | ||
369 | /* take real parameters */ | ||
370 | st->codec->codec_type = CODEC_TYPE_AUDIO; | ||
371 | st->codec->codec_id = s->codec_id; | ||
372 | st->codec->sample_rate = s->sample_rate; | ||
373 | st->codec->channels = s->channels; | ||
374 | return 0; | ||
375 | av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */ | ||
376 | } | ||
377 | |||
378 | static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) | ||
379 | { | ||
380 | AudioData *s = (AudioData *)s1->priv_data; | ||
381 | int size; | ||
382 | size_t len, amount; | ||
383 | unsigned char *buf; | ||
384 | status_t err; | ||
385 | |||
386 | if (av_new_packet(pkt, s->frame_size) < 0) | ||
387 | return AVERROR(EIO); | ||
388 | buf = (unsigned char *)pkt->data; | ||
389 | size = pkt->size; | ||
390 | while (size > 0) { | ||
391 | len = MIN(AUDIO_BLOCK_SIZE, size); | ||
392 | //printf("acquire_sem(output, %d)\n", len); | ||
393 | while ((err=acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL)) == B_INTERRUPTED); | ||
394 | if (err < B_OK) { | ||
395 | av_free_packet(pkt); | ||
396 | return AVERROR(EIO); | ||
397 | } | ||
398 | amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index)); | ||
399 | memcpy(buf, &s->buffer[s->output_index], amount); | ||
400 | s->output_index += amount; | ||
401 | if (s->output_index >= AUDIO_BUFFER_SIZE) { | ||
402 | s->output_index %= AUDIO_BUFFER_SIZE; | ||
403 | memcpy(buf + amount, &s->buffer[s->output_index], len - amount); | ||
404 | s->output_index += len-amount; | ||
405 | s->output_index %= AUDIO_BUFFER_SIZE; | ||
406 | } | ||
407 | release_sem_etc(s->input_sem, len, 0); | ||
408 | //printf("release_sem(input, %d)\n", len); | ||
409 | buf += len; | ||
410 | size -= len; | ||
411 | } | ||
412 | //XXX: add pts info | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int audio_read_close(AVFormatContext *s1) | ||
417 | { | ||
418 | AudioData *s = (AudioData *)s1->priv_data; | ||
419 | |||
420 | audio_close(s); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static AVInputFormat audio_beos_demuxer = { | ||
425 | "audio_beos", | ||
426 | NULL_IF_CONFIG_SMALL("audio grab and output"), | ||
427 | sizeof(AudioData), | ||
428 | NULL, | ||
429 | audio_read_header, | ||
430 | audio_read_packet, | ||
431 | audio_read_close, | ||
432 | NULL, | ||
433 | AVFMT_NOFILE, | ||
434 | }; | ||
435 | |||
436 | AVOutputFormat audio_beos_muxer = { | ||
437 | "audio_beos", | ||
438 | NULL_IF_CONFIG_SMALL("audio grab and output"), | ||
439 | "", | ||
440 | "", | ||
441 | sizeof(AudioData), | ||
442 | #ifdef WORDS_BIGENDIAN | ||
443 | CODEC_ID_PCM_S16BE, | ||
444 | #else | ||
445 | CODEC_ID_PCM_S16LE, | ||
446 | #endif | ||
447 | CODEC_ID_NONE, | ||
448 | audio_write_header, | ||
449 | audio_write_packet, | ||
450 | audio_write_trailer, | ||
451 | AVFMT_NOFILE, | ||
452 | }; | ||
453 | |||
454 | extern "C" { | ||
455 | |||
456 | int audio_init(void) | ||
457 | { | ||
458 | main_thid = find_thread(NULL); | ||
459 | av_register_input_format(&audio_beos_demuxer); | ||
460 | av_register_output_format(&audio_beos_muxer); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | } // "C" | ||
465 | |||