be a bit more careful to not trigger race conditions in flash
[libflashsupport-jack.git] / flashsupport.c
blobfe0be516abe90bea567a80e5b482cb752deff6f6
1 /*
2 Adobe Systems Incorporated(r) Source Code License Agreement
3 Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved.
5 Please read this Source Code License Agreement carefully before using
6 the source code.
8 Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive,
9 no-charge, royalty-free, irrevocable copyright license, to reproduce,
10 prepare derivative works of, publicly display, publicly perform, and
11 distribute this source code and such derivative works in source or
12 object code form without any attribution requirements.
14 The name "Adobe Systems Incorporated" must not be used to endorse or promote products
15 derived from the source code without prior written permission.
17 You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and
18 against any loss, damage, claims or lawsuits, including attorney's
19 fees that arise or result from your use or distribution of the source
20 code.
22 THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
23 ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
26 NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
27 OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
33 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 ////////////////////////////////////////////////////////////////////////////////////////////////////
37 // File name: flashsupport.c
38 // Targets: Adobe Flash Player 9.1 beta 2 for Linux (9.0.21.78)
39 // Last Revision Date: 11/20/2006
42 ////////////////////////////////////////////////////////////////////////////////////////////////////
44 // These are the feature which can be turned on and off. They are all
45 // optional. The ALSA and Video4Linux support in this file is somewhat
46 // redundant and reduced in functionality as the Flash Player already has
47 // ALSA and Video4Linux support built-in. It is provided here for reference only.
48 // Also, if your system has ALSA support in the kernel there is no need to
49 // enable OSS here as it will override it.
52 #define OPENSSL
53 //#define GNUTLS
54 //#define ALSA
55 //#define OSS
56 #define V4L1
57 //#define PULSEAUDIO
58 #define JACK
60 ////////////////////////////////////////////////////////////////////////////////////////////////////
62 // To compile and install flashsupport.c the following components are required:
64 // - a C compiler (gcc 4.03 is known to be working)
65 // - OpenSSL developer package and working user libraries (OpenSSL 0.9.8 is known to be working)
66 // - OSS (or ALSA) developer package and working users libraries (Linux 2.6.15 is known to be working)
67 // - sudo or root access to install the generated library to /usr/lib
69 // We suggest these steps in a terminal:
71 // > cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so
72 // > ldd libflashplayer.so
73 // > sudo cp libflashplayer.so /usr/lib
75 // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player
76 // will silently fail to load and use libflashsupport.so.
79 ////////////////////////////////////////////////////////////////////////////////////////////////////
81 // SHARED SECTION, DO NOT CHANGE!
83 #ifdef cplusplus
84 extern "C" {
85 #endif // cplusplus
88 // Imported functions
91 typedef void *(*T_FPI_Mem_Alloc)(int size); // This function is not thread safe
92 typedef void (*T_FPI_Mem_Free)(void *ptr); // This function is not thread safe
94 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
95 typedef void (*T_FPI_SoundOutput_FillBuffer)(void *ptr, char *buffer, int n_bytes); // This function is thread safe
96 #endif // defined(ALSA) || defined(OSS)
98 struct FPI_Functions {
99 int fpi_count;
100 void *fpi_mem_alloc; // 1
101 void *fpi_mem_free; // 2
102 void *fpi_soundoutput_fillbuffer; // 3
106 // Exported functions
109 void *FPX_Init(void *ptr);
111 static void FPX_Shutdown(void);
113 #if defined(OPENSSL) || defined(GNUTLS)
114 static void *FPX_SSLSocket_Create(int socket_fd);
115 static int FPX_SSLSocket_Destroy(void *ptr);
116 static int FPX_SSLSocket_Connect(void *ptr);
117 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes);
118 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes);
119 #endif // defined(OPENSSL) || defined(GNUTLS)
121 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
122 static void *FPX_SoundOutput_Open(void);
123 static int FPX_SoundOutput_Close(void *ptr);
124 static int FPX_SoundOutput_Latency(void *ptr);
125 #endif // defined(ALSA) || defined(OSS)
127 #ifdef V4L1
128 static void *FPX_VideoInput_Open(void);
129 static int FPX_VideoInput_Close(void *ptr);
130 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes);
131 #endif // V4L1
133 struct FPX_Functions {
134 int fpx_count;
135 void *fpx_shutdown; // 1
136 void *fpx_sslsocket_create; // 2
137 void *fpx_sslsocket_destroy; // 3
138 void *fpx_sslsocket_connect; // 4
139 void *fpx_sslsocket_receive; // 5
140 void *fpx_sslsocket_send; // 6
141 void *fpx_soundoutput_open; // 7
142 void *fpx_soundoutput_close; // 8
143 void *fpx_soundoutput_latency; // 9
144 void *fpx_videoinput_open; // 10
145 void *fpx_videoinput_close; // 11
146 void *fpx_videoinput_getframe; // 12
149 #ifdef cplusplus
151 #endif // cplusplus
153 // END OF SHARED SECTION
155 ////////////////////////////////////////////////////////////////////////////////////////////////////
157 #include <memory.h>
159 #ifdef OPENSSL
160 #include <openssl/ssl.h>
161 #elif defined(GNUTLS)
162 #include <sys/types.h>
163 #include <sys/socket.h>
164 #include <arpa/inet.h>
165 #include <unistd.h>
166 #include <gnutls/gnutls.h>
167 #endif // GNUTLS
169 #ifdef ALSA
170 #include <pthread.h>
171 #include <semaphore.h>
172 #include <alsa/asoundlib.h>
173 #elif defined(OSS)
174 #include <unistd.h>
175 #include <pthread.h>
176 #include <linux/soundcard.h>
177 #include <sys/ioctl.h>
178 #include <fcntl.h>
179 #endif // OSS
181 #ifdef V4L1
182 #include <unistd.h>
183 #include <pthread.h>
184 #include <linux/videodev.h>
185 #include <sys/ioctl.h>
186 #include <fcntl.h>
187 #endif // V4L1
189 #ifdef PULSEAUDIO
190 #include <pulse/pulseaudio.h>
191 #endif
193 #ifdef JACK
194 #include <jack/jack.h>
195 #include <jack/ringbuffer.h>
196 #include <jack/thread.h>
197 #include <samplerate.h>
198 #include <semaphore.h>
199 #endif
201 static struct FPX_Functions fpx_functions;
203 static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0;
204 static T_FPI_Mem_Free FPI_Mem_Free = 0;
206 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
207 static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0;
208 #endif // defined(ALSA) || defined(OSS)
210 void *FPX_Init(void *ptr)
212 struct FPI_Functions *fpi_functions;
213 if ( !ptr ) return 0;
216 // Setup imported functions
219 fpi_functions = (struct FPI_Functions *)ptr;
221 if ( fpi_functions->fpi_count >= 1 ) FPI_Mem_Alloc = fpi_functions->fpi_mem_alloc; // 1
222 if ( fpi_functions->fpi_count >= 2 ) FPI_Mem_Free = fpi_functions->fpi_mem_free; // 2
224 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
225 if ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3
226 #endif // defined(ALSA) || defined(OSS)
229 // Setup exported functions
232 memset(&fpx_functions, 0, sizeof(fpx_functions));
234 fpx_functions.fpx_shutdown = FPX_Shutdown; // 1
236 #if defined(OPENSSL) || defined(GNUTLS)
237 fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2
238 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3
239 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4
240 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5
241 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6
242 #endif // defined(OPENSSL) || defined(GNUTLS)
244 #if defined(ALSA) || defined(OSS) || defined(PULSEAUDIO) || defined(JACK)
245 fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 7
246 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 8
247 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 9
248 #endif // defined(ALSA) || defined(OSS)
250 #ifdef V4L1
251 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10
252 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11
253 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12
254 #endif // V4L1
256 fpx_functions.fpx_count = 14;
258 #ifdef OPENSSL
259 SSL_library_init();
260 #elif defined(GNUTLS)
261 gnutls_global_init();
262 #endif // GNUTLS
264 return (void *)&fpx_functions;
267 static void FPX_Shutdown(void)
269 #ifdef OPENSSL
271 #elif defined(GNUTLS)
272 gnutls_global_deinit();
273 #endif // GNUTLS
277 // SSL support functions
280 #ifdef OPENSSL
281 struct SSL_Instance {
282 SSL *ssl;
283 SSL_CTX *sslCtx;
286 static void *FPX_SSLSocket_Create(int socket_fd)
287 // return = instance pointer
289 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
290 memset(instance,0,sizeof(struct SSL_Instance));
292 if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail;
294 if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail;
296 if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail;
298 return (void *)instance;
299 fail:
300 if ( instance->ssl ) {
301 SSL_shutdown(instance->ssl);
304 if ( instance->sslCtx ) {
305 SSL_CTX_free(instance->sslCtx);
308 if (FPI_Mem_Free) FPI_Mem_Free(instance);
310 return 0;
313 static int FPX_SSLSocket_Destroy(void *ptr)
314 // ptr = instance pointer
315 // return = 0 on sucess, < 0 on error
317 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
319 if ( instance->ssl ) {
320 SSL_shutdown(instance->ssl);
323 if ( instance->sslCtx ) {
324 SSL_CTX_free(instance->sslCtx);
327 if (FPI_Mem_Free) FPI_Mem_Free(instance);
329 return 0;
332 static int FPX_SSLSocket_Connect(void *ptr)
333 // ptr = instance pointer
334 // socket_fd = BSD socket fd to be associated with SSL connection
335 // return = 0 on sucess, < 0 on error
337 // Flash Player will use errno to obtain current status
339 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
340 return SSL_connect(instance->ssl);
343 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
344 // ptr = instance pointer
345 // buffer = raw buffer to place received data into
346 // n_bytes = length of buffer in bytes
347 // return = actual bytes received, < 0 on error
349 // Flash Player will use errno to obtain current status
351 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
352 return SSL_read(instance->ssl, buffer, n_bytes);
355 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
356 // ptr = instance pointer
357 // buffer = raw buffer to be sent
358 // n_bytes = length of input buffer in bytes
359 // return = actual bytes sent, < 0 on error
361 // Flash Player will use errno to obtain current status
363 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
364 return SSL_write(instance->ssl, buffer, n_bytes);
366 #elif defined(GNUTLS)
367 struct SSL_Instance {
368 gnutls_session_t session;
369 gnutls_anon_client_credentials_t anoncred;
372 static void *FPX_SSLSocket_Create(int socket_fd)
373 // return = instance pointer
375 const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
377 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
378 memset(instance,0,sizeof(struct SSL_Instance));
380 if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail;
382 if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail;
384 if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail;
386 if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail;
388 if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail;
390 gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd);
392 return (void *)instance;
393 fail:
395 if ( instance->session ) {
396 gnutls_deinit(instance->session);
399 if ( instance->anoncred ) {
400 gnutls_anon_free_client_credentials(instance->anoncred);
403 if (FPI_Mem_Free) FPI_Mem_Free(instance);
405 return 0;
408 static int FPX_SSLSocket_Destroy(void *ptr)
409 // ptr = instance pointer
410 // return = 0 on sucess, < 0 on error
412 struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance));
414 gnutls_bye(instance->session, GNUTLS_SHUT_RDWR);
416 gnutls_deinit(instance->session);
418 gnutls_anon_free_client_credentials(instance->anoncred);
420 if (FPI_Mem_Free) FPI_Mem_Free(instance);
422 return 0;
425 static int FPX_SSLSocket_Connect(void *ptr)
426 // ptr = instance pointer
427 // socket_fd = BSD socket fd to be associated with SSL connection
428 // return = 0 on sucess, < 0 on error
430 // Flash Player will use errno to obtain current status
432 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
433 return gnutls_handshake(instance->session);
436 static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes)
437 // ptr = instance pointer
438 // buffer = raw buffer to place received data into
439 // n_bytes = length of buffer in bytes
440 // return = actual bytes received, < 0 on error
442 // Flash Player will use errno to obtain current status
444 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
445 return gnutls_record_recv(instance->session, buffer, n_bytes);
448 static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes)
449 // ptr = instance pointer
450 // buffer = raw buffer to be sent
451 // n_bytes = length of input buffer in bytes
452 // return = actual bytes sent, < 0 on error
454 // Flash Player will use errno to obtain current status
456 struct SSL_Instance *instance = (struct SSL_Instance *)ptr;
457 return gnutls_record_send(instance->session, buffer, n_bytes);
459 #endif // GNUTLS
462 // Sound support functions
464 #ifdef ALSA
465 struct SoundOutput_Instance {
466 snd_pcm_t * handle;
467 snd_async_handler_t * async_handler;
468 sem_t semaphore;
469 pthread_t thread;
470 char * buffer;
471 snd_pcm_sframes_t buffer_size;
472 snd_pcm_sframes_t period_size;
473 snd_pcm_sframes_t buffer_pos;
474 char * buffer_ptr;
477 static void *alsa_thread(void *ptr)
479 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
480 snd_pcm_sframes_t avail = 0;
481 int result = 0;
482 int err = 0;
483 int state = 0;
485 for( ; ; ) {
487 err = sem_wait(&instance->semaphore);
488 if ( !instance->handle ) {
489 pthread_exit(0);
490 return 0;
493 if ( err < 0 ) {
494 usleep(1);
495 continue;
498 do {
499 if ( instance->buffer_pos <= 0 ) {
500 FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size));
501 instance->buffer_pos = instance->period_size;
502 instance->buffer_ptr = instance->buffer;
504 do {
505 state = snd_pcm_state(instance->handle);
506 if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) {
507 snd_pcm_prepare(instance->handle);
509 result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos);
510 if( result <= 0 ) {
511 switch( result ) {
512 case -EPIPE: {
513 snd_pcm_prepare(instance->handle);
514 } break;
515 case -ESTRPIPE: {
516 err = snd_pcm_resume(instance->handle);
517 if ( err < 0 ) {
518 snd_pcm_prepare(instance->handle);
520 } break;
522 break;
523 } else {
524 instance->buffer_pos -= result;
525 instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result);
527 } while (instance->buffer_pos);
528 avail = snd_pcm_avail_update(instance->handle);
529 if( avail < 0 ) {
530 switch( avail ) {
531 case -EPIPE: {
532 snd_pcm_prepare(instance->handle);
533 } break;
534 case -ESTRPIPE: {
535 err = snd_pcm_resume(instance->handle);
536 if ( err < 0 ) {
537 snd_pcm_prepare(instance->handle);
539 } break;
541 break;
544 } while(avail >= instance->period_size);
548 static void alsa_callback(snd_async_handler_t *ahandler)
550 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler);
551 // signal mixer thread
552 sem_post(&instance->semaphore);
555 static void *FPX_SoundOutput_Open()
556 // return = instance pointer
558 struct SoundOutput_Instance *instance = 0;
559 snd_pcm_hw_params_t *hwparams = 0;
560 snd_pcm_sw_params_t *swparams = 0;
561 snd_pcm_format_t pcm_format;
562 unsigned int buffer_time = 500000;
563 unsigned int period_time = 20000;
564 unsigned int actual_rate;
565 snd_pcm_uframes_t size;
566 int direction;
567 void *retVal = 0;
568 int err = 0;
570 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
571 if ( !FPI_Mem_Alloc ) goto fail;
573 instance = FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
574 memset(instance,0,sizeof(struct SoundOutput_Instance));
576 if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
577 if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) {
578 goto fail;
582 snd_pcm_hw_params_alloca(&hwparams);
583 snd_pcm_sw_params_alloca(&swparams);
585 if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail;
587 if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail;
589 pcm_format = SND_PCM_FORMAT_S16_LE;
591 if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail;
593 if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail;
595 actual_rate = 44100;
597 if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail;
599 if (actual_rate != 44100) goto fail;
601 if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail;
603 if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail;
605 instance->buffer_size = (snd_pcm_sframes_t)size;
607 if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail;
609 if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail;
611 instance->period_size = (snd_pcm_sframes_t)size;
613 if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail;
615 if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail;
617 if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail;
619 if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail;
621 if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail;
623 if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail;
625 if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail;
627 if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail;
629 if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail;
631 if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail;
633 sem_post(&instance->semaphore);
635 return instance;
637 fail:
638 if ( instance ) {
639 if ( instance->handle ) {
640 snd_pcm_drop(instance->handle);
641 snd_pcm_close(instance->handle);
642 instance->handle = 0;
644 if ( instance->thread ) {
645 sem_post(&instance->semaphore);
646 sem_destroy(&instance->semaphore);
647 pthread_join(instance->thread,&retVal);
649 if ( instance->buffer ) {
650 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
652 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
654 return 0;
657 static int FPX_SoundOutput_Close(void *ptr)
658 // ptr = instance pointer
659 // return = 0 on success, < 0 on error
661 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
662 void *retVal = 0;
663 if ( instance->handle ) {
664 snd_pcm_drop(instance->handle);
665 snd_pcm_close(instance->handle);
666 instance->handle = 0;
668 if ( instance->thread ) {
669 sem_post(&instance->semaphore);
670 sem_destroy(&instance->semaphore);
671 pthread_join(instance->thread,&retVal);
673 if ( instance->buffer ) {
674 if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer);
676 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
677 return 0;
680 static int FPX_SoundOutput_Latency(void *ptr)
681 // ptr = instance pointer
682 // return = 0 on success, < 0 on error
684 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
685 if ( instance->handle ) {
686 snd_pcm_sframes_t delay = 0;
687 snd_pcm_delay(instance->handle, &delay);
688 if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) {
689 return delay;
690 } else {
691 return 0;
694 return -1;
696 #elif defined(OSS)
697 struct SoundOutput_Instance {
698 int oss_fd;
699 pthread_t thread;
700 int signal;
703 static void *oss_thread(void *ptr)
705 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
706 char buffer[4096];
707 int len = 0;
708 int written = 0;
709 for(;;) {
710 FPI_SoundOutput_FillBuffer(ptr,buffer,4096);
711 len = 4096;
712 while ( len ) {
713 written = write(instance->oss_fd, buffer, len);
714 if ( written >= 0 ) {
715 len -= written;
717 if ( instance->signal ) {
718 pthread_exit(0);
720 if ( written < 0 ) {
721 usleep(100);
727 static void *FPX_SoundOutput_Open()
728 // return = instance pointer
730 struct SoundOutput_Instance *instance = 0;
731 int format = AFMT_S16_LE;
732 int stereo = 1;
733 int speed = 44100;
735 if ( !FPI_SoundOutput_FillBuffer ) goto fail;
736 if ( !FPI_Mem_Alloc ) goto fail;
738 instance = (struct SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct SoundOutput_Instance));
739 memset(instance,0,sizeof(struct SoundOutput_Instance));
741 if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail;
743 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail;
745 if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail;
747 if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail;
749 if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail;
751 return instance;
752 fail:
753 if ( instance ) {
754 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
756 return 0;
759 static int FPX_SoundOutput_Close(void *ptr)
760 // ptr = instance pointer
761 // return = 0 on success, < 0 on error
763 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
764 void *retVal = 0;
766 instance->signal = 1;
768 if ( instance->oss_fd ) {
769 ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0);
772 if ( instance->thread ) {
773 pthread_join(instance->thread,&retVal);
776 if ( instance->oss_fd ) {
777 close(instance->oss_fd);
780 if ( FPI_Mem_Free ) FPI_Mem_Free(instance);
782 return 0;
785 static int FPX_SoundOutput_Latency(void *ptr)
786 // ptr = instance pointer
787 // return = 0 on success, < 0 on error
789 struct SoundOutput_Instance *instance = (struct SoundOutput_Instance *)ptr;
790 if ( instance->oss_fd ) {
791 int value = 0;
792 if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) {
793 return value / 4;
795 return 0;
797 return -1;
799 #endif // defined(OSS)
801 #ifdef PULSEAUDIO
803 #define BUFSIZE (4096)
805 struct output_data {
806 pa_threaded_mainloop *mainloop;
807 pa_context *context;
808 pa_stream *stream;
809 uint8_t buf[BUFSIZE];
810 pthread_t thread_id;
811 int first;
814 static void context_state_cb(pa_context *c, void *userdata) {
815 struct output_data *p = userdata;
817 assert(c);
818 assert(p);
820 p->thread_id = pthread_self();
821 p->context = c;
823 switch (pa_context_get_state(c)) {
824 case PA_CONTEXT_READY:
825 case PA_CONTEXT_TERMINATED:
826 case PA_CONTEXT_FAILED:
827 pa_threaded_mainloop_signal(p->mainloop, 0);
828 break;
830 case PA_CONTEXT_UNCONNECTED:
831 case PA_CONTEXT_CONNECTING:
832 case PA_CONTEXT_AUTHORIZING:
833 case PA_CONTEXT_SETTING_NAME:
834 break;
838 static void stream_state_cb(pa_stream *s, void *userdata) {
839 struct output_data *p = userdata;
841 assert(s);
842 assert(p);
844 p->thread_id = pthread_self();
845 p->stream = s;
847 switch (pa_stream_get_state(s)) {
849 case PA_STREAM_READY:
850 case PA_STREAM_FAILED:
851 case PA_STREAM_TERMINATED:
852 pa_threaded_mainloop_signal(p->mainloop, 0);
853 break;
855 case PA_STREAM_UNCONNECTED:
856 case PA_STREAM_CREATING:
857 break;
861 static void write_data(struct output_data *p) {
862 size_t length;
864 assert(p);
866 /* Wait until timing info is available before we write the second
867 * and all subsequent blocks */
868 if (!p->first && !pa_stream_get_timing_info(p->stream))
869 return;
871 length = pa_stream_writable_size(p->stream);
873 while (length > 4) {
874 size_t l = length;
876 if (l > BUFSIZE)
877 l = BUFSIZE;
879 l &= ~ ((size_t) 3);
881 FPI_SoundOutput_FillBuffer(p, (char*) p->buf, l);
883 if (pa_stream_write(p->stream, p->buf, l, NULL, 0, PA_SEEK_RELATIVE) < 0)
884 break;
886 length -= l;
888 if (p->first)
889 break;
892 /* There's no real handling of errors here. Unfortunately the
893 * Flash API doesn't export a sane way to do this. With networked
894 * audio streams and hotplug-capable audio devices the audio
895 * stream might be killed in the middle of nothing, hence it is
896 * very unfortunate that we cannot report errors that happen here
897 * back to Flash. */
899 p->first = 0; /* So, we write the first block noch, remember that */
902 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
903 struct output_data *p = userdata;
905 assert(s);
906 assert(length > 0);
907 assert(p);
909 p->thread_id = pthread_self();
911 /* Write some data */
912 write_data(p);
915 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
916 struct output_data *p = userdata;
918 assert(s);
919 assert(p);
921 p->thread_id = pthread_self();
923 /* Try to write some more, in case we delayed the first write until latency data became available */
924 write_data(p);
927 static void *FPX_SoundOutput_Open(void) {
929 static const pa_sample_spec ss = {
930 .format = PA_SAMPLE_S16LE, /* Hmm, Flash wants LE here, not
931 * NE. This makes porting Flash to
932 * Big-Endian machines unnecessary
933 * difficult. */
934 .rate = 44100,
935 .channels = 2
938 struct output_data *p;
940 /* Unfortunately we cannot report any useful error string back to
941 * Flash. It would be highly preferable if Flash supported some
942 * way how we could tell the user what the reason is why audio is
943 * not working for him. */
945 if (!(p = FPI_Mem_Alloc(sizeof(struct output_data))))
946 goto fail;
948 memset(p, 0, sizeof(*p));
949 p->first = 1;
950 p->thread_id = (pthread_t) 0;
952 /* First, let's create the main loop */
953 if (!(p->mainloop = pa_threaded_mainloop_new()))
954 goto fail;
956 /* Second, initialize the connection context */
957 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), "Adobe Flash")))
958 goto fail;
960 pa_context_set_state_callback(p->context, context_state_cb, p);
962 if (pa_context_connect(p->context, NULL, 0, NULL) < 0)
963 goto fail;
965 /* Now, let's start the background thread */
966 pa_threaded_mainloop_lock(p->mainloop);
968 if (pa_threaded_mainloop_start(p->mainloop) < 0)
969 goto fail;
971 /* Wait until the context is ready */
972 pa_threaded_mainloop_wait(p->mainloop);
974 if (pa_context_get_state(p->context) != PA_CONTEXT_READY)
975 goto unlock_and_fail;
977 /* Now, initialize the stream */
978 if (!(p->stream = pa_stream_new(p->context, "Flash Animation", &ss, NULL)))
979 goto unlock_and_fail;
981 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
982 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
983 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
985 if (pa_stream_connect_playback(p->stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
986 goto unlock_and_fail;
988 /* Wait until the stream is ready */
989 pa_threaded_mainloop_wait(p->mainloop);
991 if (pa_stream_get_state(p->stream) != PA_STREAM_READY)
992 goto unlock_and_fail;
994 pa_threaded_mainloop_unlock(p->mainloop);
996 return p;
998 unlock_and_fail:
1000 pa_threaded_mainloop_unlock(p->mainloop);
1002 fail:
1003 if (p)
1004 FPX_SoundOutput_Close(p);
1006 return NULL;
1009 static int FPX_SoundOutput_Close(void *ptr) {
1010 struct output_data *p = ptr;
1012 assert(p);
1014 if (p->mainloop)
1015 pa_threaded_mainloop_stop(p->mainloop);
1017 if (p->stream) {
1018 pa_stream_disconnect(p->stream);
1019 pa_stream_unref(p->stream);
1022 if (p->context) {
1023 pa_context_disconnect(p->context);
1024 pa_context_unref(p->context);
1027 if (p->mainloop)
1028 pa_threaded_mainloop_free(p->mainloop);
1030 if (FPI_Mem_Free)
1031 FPI_Mem_Free(p);
1033 return 0;
1036 static int FPX_SoundOutput_Latency(void *ptr) {
1037 struct output_data *p = ptr;
1038 pa_usec_t t = 0;
1039 int negative;
1040 int r;
1042 assert(p);
1044 /* We lock here only if we are not called from our event loop thread */
1045 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1046 pa_threaded_mainloop_lock(p->mainloop);
1048 if (pa_stream_get_latency(p->stream, &t, &negative) < 0 || negative)
1049 r = 0;
1050 else
1051 r = (int) (pa_usec_to_bytes(t, pa_stream_get_sample_spec(p->stream)) >> 2);
1053 if (!p->thread_id || !pthread_equal(p->thread_id, pthread_self()))
1054 pa_threaded_mainloop_unlock(p->mainloop);
1056 return r;
1059 #endif
1061 #ifdef JACK
1063 struct jack_output_data {
1064 jack_client_t *client;
1065 jack_port_t *port_l;
1066 jack_port_t *port_r;
1067 SRC_STATE *src_l;
1068 SRC_STATE *src_r;
1069 int src_error;
1071 jack_ringbuffer_t *buffer;
1072 sem_t semaphore;
1073 volatile int quit;
1074 pthread_t tid;
1077 static void *jack_flash_thread( void *arg )
1079 struct jack_output_data *p = arg;
1080 int jack_rate = jack_get_sample_rate( p->client );
1081 int flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1083 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1084 int16_t *buffer = alloca( bufsize );
1086 sem_wait( &(p->semaphore) );
1087 usleep( 50 );
1089 while( !p->quit ) {
1090 sem_wait( &(p->semaphore) );
1091 FPI_SoundOutput_FillBuffer(p, (char*) buffer, bufsize);
1092 if( jack_ringbuffer_write( p->buffer, (char*)buffer, bufsize ) != bufsize )
1093 printf( "something is wrong\n" );
1096 return NULL;
1099 static int jack_process_cb( jack_nframes_t nframes, void *arg )
1101 struct jack_output_data *p = arg;
1102 int i;
1103 int jack_rate = jack_get_sample_rate( p->client );
1104 int flash_frames = nframes * 44100 / jack_rate;
1106 size_t bufsize = 2*flash_frames * sizeof( int16_t );
1107 int16_t *buffer = alloca( bufsize );
1108 float *float_buf = alloca( flash_frames * sizeof(float) );
1110 float *port_l = jack_port_get_buffer( p->port_l, nframes );
1111 float *port_r = jack_port_get_buffer( p->port_r, nframes );
1113 SRC_DATA sd;
1115 if( jack_ringbuffer_read_space( p->buffer ) < bufsize ) {
1116 // no data to read. fill ports with zero and return.
1117 memset( port_l, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1118 memset( port_r, 0, nframes * sizeof( jack_default_audio_sample_t ) );
1119 return 0;
1122 if( jack_ringbuffer_read( p->buffer, (char *)buffer, bufsize ) != bufsize ) {
1123 printf( "Something is pretty wrong :( \n" );
1124 return 0;
1126 sem_post( &(p->semaphore) );
1128 for( i=0; i<flash_frames; i++ ) {
1129 float_buf[i] = (float) (buffer[2*i]) / 32768.0;
1132 sd.data_in = float_buf;
1133 sd.data_out = port_l;
1134 sd.input_frames = flash_frames;
1135 sd.output_frames = nframes;
1136 sd.end_of_input = 0;
1137 // sd.src_ratio = (double)flash_frames / (double)nframes;
1138 sd.src_ratio = (double)nframes / (double)flash_frames;
1140 src_process( p->src_l, &sd );
1143 for( i=0; i<flash_frames; i++ ) {
1144 float_buf[i] = (float) (buffer[2*i+1]) / 32768.0;
1147 sd.data_in = float_buf;
1148 sd.data_out = port_r;
1149 sd.input_frames = flash_frames;
1150 sd.output_frames = nframes;
1151 sd.end_of_input = 0;
1152 // sd.src_ratio = (double)flash_frames / (double)nframes;
1153 sd.src_ratio = (double)nframes / (double)flash_frames;
1155 src_process( p->src_r, &sd );
1157 return 0;
1160 static void *FPX_SoundOutput_Open(void) {
1162 struct jack_output_data *p=NULL;
1163 char namebuf[100];
1164 int jack_rate;
1165 int flash_frames;
1166 size_t bufsize;
1167 int i;
1169 /* Unfortunately we cannot report any useful error string back to
1170 * Flash. It would be highly preferable if Flash supported some
1171 * way how we could tell the user what the reason is why audio is
1172 * not working for him. */
1174 if (!(p = FPI_Mem_Alloc(sizeof(struct jack_output_data))))
1175 goto fail;
1177 memset(p, 0, sizeof(*p));
1179 p->src_l = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1180 p->src_r = src_new(SRC_SINC_FASTEST, 1, & (p->src_error));
1183 /* First, let's create the main loop */
1184 if (!(p->client = jack_client_open( "flash", 0, NULL )))
1185 goto fail;
1187 jack_rate = jack_get_sample_rate( p->client );
1188 flash_frames = jack_get_buffer_size( p->client ) * 44100 / jack_rate;
1189 bufsize = 2*flash_frames * sizeof( int16_t );
1191 p->buffer = jack_ringbuffer_create( bufsize * 6 );
1192 sem_init( &(p->semaphore), 0, 0 );
1194 pthread_create( &(p->tid), NULL, jack_flash_thread, p );
1195 #if 0
1196 // This seems to trigger a race condition in flash.
1198 jack_client_create_thread( p->client,
1199 &(p->tid),
1200 (jack_client_real_time_priority( p->client ) == -1) ? 1 : (jack_client_real_time_priority( p->client ) - 1),
1201 (jack_client_real_time_priority( p->client ) == -1) ? 0 : 1,
1202 jack_flash_thread,
1203 p );
1204 #endif
1207 /* Second, initialize the connection context */
1208 if (!(p->port_l = jack_port_register( p->client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1209 goto fail;
1210 if (!(p->port_r = jack_port_register( p->client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) )
1211 goto fail;
1213 jack_set_process_callback( p->client, jack_process_cb, p );
1214 jack_activate( p->client );
1216 snprintf( namebuf, 99, "%s:out1", jack_get_client_name( p->client ) );
1217 jack_connect( p->client, namebuf, "system:playback_1" );
1218 snprintf( namebuf, 99, "%s:out2", jack_get_client_name( p->client ) );
1219 jack_connect( p->client, namebuf, "system:playback_2" );
1221 // Now start the fill thread.
1222 // the semaphore represents the number of writeable buffers in
1223 // the ringbuffer. we add 1 for the initial sem_wait.
1225 for(i=0; i<( 5 + 1 ); i++ )
1226 sem_post( &(p->semaphore) );
1228 return p;
1230 fail:
1231 if (p)
1232 FPX_SoundOutput_Close(p);
1234 return NULL;
1237 static int FPX_SoundOutput_Close(void *ptr) {
1238 struct jack_output_data *p = ptr;
1240 //assert(p);
1241 if( p->tid ) {
1242 p->quit = 1;
1243 pthread_join( p->tid, NULL );
1246 if (p->client) {
1247 jack_deactivate( p->client );
1248 jack_client_close( p->client );
1251 return 0;
1254 static int FPX_SoundOutput_Latency(void *ptr) {
1255 // heh ? jack has no latency :P
1256 struct jack_output_data *p = ptr;
1257 return jack_ringbuffer_read_space( p->buffer ) / 4;
1259 #endif
1262 #ifdef V4L1
1263 struct VideoOutput_Instance {
1264 int v4l_fd;
1265 pthread_t thread;
1266 int signal;
1267 char * buffer[2];
1268 int buffercurrent;
1269 int buffersize;
1270 struct video_window window;
1271 struct video_picture picture;
1274 static void *v4l_thread(void *ptr)
1276 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1277 int result;
1278 int status;
1280 for(;;) {
1282 result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize);
1283 if(result > 0) {
1286 if ( result < 0 ) {
1287 usleep(10000);
1290 if ( instance->signal ) {
1291 status = 0;
1292 ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status);
1293 pthread_exit(0);
1296 return NULL;
1299 static void *FPX_VideoInput_Open(void)
1301 struct VideoOutput_Instance *instance = 0;
1303 if ( !FPI_Mem_Alloc ) goto fail;
1305 instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance));
1306 memset(instance,0,sizeof(struct VideoOutput_Instance));
1308 if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail;
1310 if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail;
1312 switch(instance->picture.palette) {
1313 case VIDEO_PALETTE_YUV420P:
1314 break;
1315 case VIDEO_PALETTE_RGB24:
1316 case VIDEO_PALETTE_YUV422P:
1317 case VIDEO_PALETTE_YUV411P:
1318 case VIDEO_PALETTE_YUV410P:
1319 case VIDEO_PALETTE_GREY:
1320 case VIDEO_PALETTE_HI240:
1321 case VIDEO_PALETTE_RGB565:
1322 case VIDEO_PALETTE_RGB32:
1323 case VIDEO_PALETTE_RGB555:
1324 case VIDEO_PALETTE_YUV422:
1325 case VIDEO_PALETTE_YUYV:
1326 case VIDEO_PALETTE_UYVY:
1327 case VIDEO_PALETTE_YUV420:
1328 case VIDEO_PALETTE_YUV411:
1329 case VIDEO_PALETTE_RAW:
1330 default:
1331 goto fail;
1334 if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail;
1336 instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1337 instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2);
1339 if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail;
1341 return instance;
1343 fail:
1344 if ( FPI_Mem_Free ) {
1345 if ( instance->buffer[0] ) {
1346 FPI_Mem_Free(instance->buffer[0]);
1348 if ( instance->buffer[1] ) {
1349 FPI_Mem_Free(instance->buffer[1]);
1351 FPI_Mem_Free(instance);
1353 return 0;
1356 static int FPX_VideoInput_Close(void *ptr)
1358 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1359 void *retVal = 0;
1361 instance->signal = 1;
1363 if ( instance->thread ) {
1364 pthread_join(instance->thread,&retVal);
1367 if ( instance->v4l_fd ) {
1368 close(instance->v4l_fd);
1371 if ( FPI_Mem_Free ) {
1372 if ( instance->buffer[0] ) {
1373 FPI_Mem_Free(instance->buffer[0]);
1375 if ( instance->buffer[1] ) {
1376 FPI_Mem_Free(instance->buffer[1]);
1378 FPI_Mem_Free(instance);
1381 return 0;
1384 static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes)
1386 struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr;
1387 int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B;
1388 unsigned char *y, *u, *v;
1390 switch(instance->picture.palette) {
1391 case VIDEO_PALETTE_YUV420P: {
1392 ow = instance->window.width;
1393 oh = instance->window.height;
1395 dx = (ow<<16) / width;
1396 dy = (oh<<16) / height;
1398 y = (unsigned char *)instance->buffer[instance->buffercurrent^1];
1399 u = y + ow * oh;
1400 v = u + ow * oh / 4;
1402 oy = 0;
1404 for ( iy = 0; iy < height; iy++ ) {
1406 ox = 0;
1408 for ( ix = 0; ix < width; ix++ ) {
1410 Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2;
1411 U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1412 V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128;
1414 R = (Y + V * 102 ) / 64;
1415 G = (Y - V * 52 - U * 25 ) / 64;
1416 B = (Y + U * 129 ) / 64;
1418 R = R < 0 ? 0 : ( R > 255 ? 255 : R );
1419 G = G < 0 ? 0 : ( G > 255 ? 255 : G );
1420 B = B < 0 ? 0 : ( B > 255 ? 255 : B );
1422 data[ix*3+0] = R;
1423 data[ix*3+1] = G;
1424 data[ix*3+2] = B;
1426 ox += dx;
1429 oy += dy;
1431 data += pitch_n_bytes;
1433 } break;
1434 default:
1435 goto fail;
1438 instance->buffercurrent ^= 1;
1440 return 0;
1442 fail:
1443 return -1;
1445 #endif // V4L1