/* Adobe Systems Incorporated(r) Source Code License Agreement Copyright(c) 2006 Adobe Systems Incorporated. All rights reserved. Please read this Source Code License Agreement carefully before using the source code. Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license, to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute this source code and such derivative works in source or object code form without any attribution requirements. The name "Adobe Systems Incorporated" must not be used to endorse or promote products derived from the source code without prior written permission. You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and against any loss, damage, claims or lawsuits, including attorney's fees that arise or result from your use or distribution of the source code. THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The Sound detection routines, ESD and PulseAudio backends have been writen by Jean-Michel Dault cc -shared -O2 -Wall -Werror -lssl flashsupport.c -o libflashsupport.so // > ldd libflashplayer.so // > sudo cp libflashplayer.so /usr/lib // // Make sure that 'ldd' can resolve all dynamic libraries. Otherwise the Flash Player // will silently fail to load and use libflashsupport.so. // //////////////////////////////////////////////////////////////////////////////////////////////////// // // SHARED SECTION, DO NOT CHANGE! // #ifdef cplusplus extern "C" { #endif // cplusplus // // Imported functions // typedef void *(*T_FPI_Mem_Alloc)(int size); // This function is not thread safe typedef void (*T_FPI_Mem_Free)(void *ptr); // This function is not thread safe #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) typedef void (*T_FPI_SoundOutput_FillBuffer)(void *ptr, char *buffer, int n_bytes); // This function is thread safe #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) struct FPI_Functions { int fpi_count; void *fpi_mem_alloc; // 1 void *fpi_mem_free; // 2 void *fpi_soundoutput_fillbuffer; // 3 }; // // Exported functions // void *FPX_Init(void *ptr); static void FPX_Shutdown(void); #if defined(OPENSSL) || defined(GNUTLS) static void *FPX_SSLSocket_Create(int socket_fd); static int FPX_SSLSocket_Destroy(void *ptr); static int FPX_SSLSocket_Connect(void *ptr); static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes); static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes); #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) static void *ALSA_FPX_SoundOutput_Open(void); static int ALSA_FPX_SoundOutput_Close(void *ptr); static int ALSA_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ALSA) #if defined(OSS) static void *OSS_FPX_SoundOutput_Open(void); static int OSS_FPX_SoundOutput_Close(void *ptr); static int OSS_FPX_SoundOutput_Latency(void *ptr); #endif // defined(OSS) #if defined(ESD) static void *ESD_FPX_SoundOutput_Open(void); static int ESD_FPX_SoundOutput_Close(void *ptr); static int ESD_FPX_SoundOutput_Latency(void *ptr); #endif // defined(ESD) #if defined(PULSEAUDIO) static void *PULSEAUDIO_FPX_SoundOutput_Open(void); static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr); static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr); #endif // defined(PULSEAUDIO) #ifdef V4L1 static void *FPX_VideoInput_Open(); static int FPX_VideoInput_Close(void *ptr); static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes); #endif // V4L1 struct FPX_Functions { int fpx_count; void *fpx_shutdown; // 1 void *fpx_sslsocket_create; // 2 void *fpx_sslsocket_destroy; // 3 void *fpx_sslsocket_connect; // 4 void *fpx_sslsocket_receive; // 5 void *fpx_sslsocket_send; // 6 void *fpx_soundoutput_open; // 7 void *fpx_soundoutput_close; // 8 void *fpx_soundoutput_latency; // 9 void *fpx_videoinput_open; // 10 void *fpx_videoinput_close; // 11 void *fpx_videoinput_getframe; // 12 }; #ifdef cplusplus }; #endif // cplusplus // // END OF SHARED SECTION // //////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #ifdef OPENSSL #include #elif defined(GNUTLS) #include #include #include #include #include #endif // GNUTLS #ifdef ALSA #include #include #include #endif #if defined(OSS) #include #include #include #include #include #endif #if defined(ESD) #include #include #include #include #include #endif #if defined(PULSEAUDIO) #include #include #include #include #endif #ifdef V4L1 #include #include #include #include #include #endif // V4L1 //Includes for output driver detection #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #include //getenv #include //stat #include //stat #include //stat #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) static struct FPX_Functions fpx_functions; static T_FPI_Mem_Alloc FPI_Mem_Alloc = 0; static T_FPI_Mem_Free FPI_Mem_Free = 0; #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) static T_FPI_SoundOutput_FillBuffer FPI_SoundOutput_FillBuffer = 0; #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) /* JMD: Choose between multiple audio interfaces by order of priority: - Pulse is always first, since it can support esound, gstreamer, alsa, oss and jack and is easily identified by environment variables or socket. Supports full audio/video synchronization, even over the network. - Esound is second, since it's by default in many distributions, and supports oss. NOTE: audio and video are not synchronized, since the latency functions can hang the browser. - Arts (TODO) is next. It's not currently supported because it's being phased out. Besides, it can use Esound as a backend - NASD: Not supported for the moment, there is not much information available... - Jack (TODO). When it's done, it should go after Pulse, but before ALSA. - ALSA: default if it's supported - Finally, if nothing else, fallback on oss */ #define AUDIO_PULSE 128 #define AUDIO_ESD 64 #define AUDIO_ARTS 32 #define AUDIO_NAS 16 #define AUDIO_JACK 8 #define AUDIO_ALSA 2 #define AUDIO_OSS 1 #if defined(ESD) //ESD functions int (*FPX_esd_play_stream_fallback)( esd_format_t format, int rate, const char *host, const char *name ); #endif #if defined(PULSEAUDIO) //PULSE functions pa_simple* (*FPX_pa_simple_new) (const char *server,const char *name, pa_stream_direction_t dir,const char *dev,const char *stream_name, const pa_sample_spec *ss,const pa_channel_map *map, const pa_buffer_attr *attr,int *error); void (*FPX_pa_simple_free) (pa_simple *s); int (*FPX_pa_simple_write) (pa_simple *s, const void*data, size_t length, int *error); int (*FPX_pa_simple_drain) (pa_simple *s, int *error); int (*FPX_pa_simple_read) (pa_simple *s, void*data, size_t length, int *error); pa_usec_t (*FPX_pa_simple_get_latency) (pa_simple *s, int *error); int (*FPX_pa_simple_flush) (pa_simple *s, int *error); const char* (*FPX_pa_strerror) (int error); #endif static int audiotype=2; static int audiodrivers=0; static int audiodebug=0; static int pulsedebug=0; void FPX_SoundOutput_Detect() { char *tmpenv; struct stat buf; #if defined(PULSEAUDIO) || defined(ESD) void *handle; char *error; #endif #if defined(PULSEAUDIO) char tmpstr[1024]=""; #endif if((tmpenv=getenv("FLASH_AUDIODEBUG"))!=NULL) { audiodebug=1; } if((tmpenv=getenv("FLASH_PULSEDEBUG"))!=NULL) { pulsedebug=1; } if(audiodebug) { fprintf( stderr,"Flash sound output detection routine.\n"); fprintf( stderr,"(c) 2006 Revolution Linux inc,\n"); fprintf( stderr,"Jean-Michel Dault \n"); } #if defined(PULSEAUDIO) //Check if PULSE AUDIO is running if((tmpenv=getenv("USER"))!=NULL) { strcpy(tmpstr,"/tmp/pulse-"); strcat(tmpstr,tmpenv); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio socket found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } } //Check if PULSE AUDIO is running system-wide strcpy(tmpstr,"/var/lib/run/pulse/native"); if(!stat(tmpstr,&buf)) { if(audiodebug) fprintf( stderr, "PulseAudio system-wide found\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse over network if((tmpenv=getenv("PULSE_SERVER"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio SERVER variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } //Pulse autospawn daemon if((tmpenv=getenv("PULSE_BINARY"))!=NULL) { if(audiodebug) fprintf( stderr, "PulseAudio BINARY variable present\n"); audiodrivers = audiodrivers | AUDIO_PULSE; } #endif #if defined(ESD) //Check if ESD is running if(!stat("/tmp/.esd/socket",&buf)) { if(audiodebug) fprintf( stderr, "ESD socket found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } //ESD over network if((tmpenv=getenv("ESPEAKER"))!=NULL) { if(audiodebug) fprintf( stderr, "ESD variable ESPEAKER found\n"); audiodrivers = audiodrivers | AUDIO_ESD; } #endif #if defined(ALSA) || defined(ALSA_INTERNAL) //Check for ALSA device if(!stat("/proc/asound",&buf)) { if(audiodebug) fprintf( stderr, "ALSA device detected\n"); audiodrivers = audiodrivers | AUDIO_ALSA; } #endif #if defined(OSS) //Check for OSS device if(!stat("/dev/dsp",&buf)) { if(audiodebug) fprintf( stderr, "OSS device present\n"); audiodrivers = audiodrivers | AUDIO_OSS; } #endif if((tmpenv=getenv("FLASH_FORCE_PULSEAUDIO"))!=NULL) { #if defined(PULSEAUDIO) if(audiodebug) fprintf( stderr, "Forcing PulseAudio\n"); audiodrivers = AUDIO_PULSE; #else if(audiodebug) fprintf( stderr, "PulseAudio unavailable: please recompile libflashsupport.so!\n"); #endif } if((tmpenv=getenv("FLASH_FORCE_ESD"))!=NULL) { #if defined(ESD) if(audiodebug) fprintf( stderr, "Forcing ESD\n"); audiodrivers = AUDIO_ESD; #else if(audiodebug) fprintf( stderr, "ESD unavailable: please recompile libflashsupport.so!\n"); #endif } if((tmpenv=getenv("FLASH_FORCE_ALSA"))!=NULL) { #if defined(ALSA) || defined(ALSA_INTERNAL) if(audiodebug) fprintf( stderr, "Forcing ALSA\n"); audiodrivers = AUDIO_ALSA; #else if(audiodebug) fprintf( stderr, "ALSA unavailable: please recompile libflashsupport.so!\n"); #endif } if((tmpenv=getenv("FLASH_FORCE_OSS"))!=NULL) { #if defined(OSS) if(audiodebug) fprintf( stderr, "Forcing OSS\n"); audiodrivers = AUDIO_OSS; #else if(audiodebug) fprintf( stderr, "OSS unavailable: please recompile libflashsupport.so!\n"); #endif } //Check for required libraries and functions #if defined(PULSEAUDIO) if((audiodrivers & AUDIO_PULSE) && !FPX_pa_simple_new) { handle = dlopen(LIBPULSEPATH, RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load %s: %s\n",LIBPULSEPATH,dlerror()); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_simple_new = dlsym(handle, "pa_simple_new"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_simple_write = dlsym(handle, "pa_simple_write"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_simple_drain = dlsym(handle, "pa_simple_drain"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_simple_free = dlsym(handle, "pa_simple_free"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_simple_get_latency = dlsym(handle, "pa_simple_get_latency"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } FPX_pa_strerror = dlsym(handle, "pa_strerror"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_PULSE); } } #endif #if defined(ESD) if((audiodrivers & AUDIO_ESD) && !FPX_esd_play_stream_fallback) { handle = dlopen(LIBESDPATH, RTLD_LAZY); if (!handle) { if(audiodebug) fprintf(stderr,"Can't load %s: %s\n",LIBESDPATH,dlerror()); audiodrivers = audiodrivers & (~AUDIO_ESD); } FPX_esd_play_stream_fallback = dlsym(handle, "esd_play_stream_fallback"); if ((error = dlerror()) != NULL) { if(audiodebug) fprintf(stderr, "%s\n", error); audiodrivers = audiodrivers & (~AUDIO_ESD); } } #endif return; } static void *FPX_SoundOutput_Open(void) { void *ptr; if(audiodebug) fprintf( stderr,"audiodrivers=%d\n",audiodrivers); #if defined(PULSEAUDIO) if(audiodrivers & AUDIO_PULSE) { if(audiodebug) fprintf( stderr,"Trying PULSE\n"); ptr=PULSEAUDIO_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_PULSE; if(audiodebug) fprintf( stderr, "Using PulseAudio driver\n"); return ptr; } } #endif #if defined(ESD) if(audiodrivers & AUDIO_ESD) { if(audiodebug) fprintf( stderr,"Trying ESD\n"); ptr=ESD_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ESD; if(audiodebug) fprintf( stderr, "Using Esound audio driver\n"); return ptr; } } #endif #if defined(ALSA_INTERNAL) if(audiodrivers & AUDIO_ALSA) { if(audiodebug) fprintf( stderr,"Using *INTERNAL* ALSA\n"); return 0; } #endif #if defined(ALSA) if(audiodrivers & AUDIO_ALSA) { if(audiodebug) fprintf( stderr,"Trying ALSA\n"); ptr=ALSA_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_ALSA; if(audiodebug) fprintf( stderr, "Using ALSA audio driver\n"); return ptr; } } #endif #if defined(OSS) if(audiodrivers & AUDIO_OSS) { if(audiodebug) fprintf( stderr,"Trying OSS\n"); ptr=OSS_FPX_SoundOutput_Open(); if(audiodebug) fprintf( stderr,"ptr=%d\n",(int)ptr); if(ptr) { audiotype=AUDIO_OSS; if(audiodebug) fprintf( stderr, "Using OSS audio driver\n"); return ptr; } } #endif // No sound... if(audiodebug) fprintf( stderr, "NO SOUND DRIVER! Revert to internal ALSA driver!\n"); return 0; } static int FPX_SoundOutput_Close(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(ALSA) if(audiotype == AUDIO_ALSA) { retcode=ALSA_FPX_SoundOutput_Close(ptr); return retcode; } #endif #if defined(OSS) if(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Close(ptr); return retcode; } #endif return 0; } static int FPX_SoundOutput_Latency(void *ptr) { int retcode; #if defined(PULSEAUDIO) if(audiotype == AUDIO_PULSE) { retcode=PULSEAUDIO_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(ESD) if(audiotype == AUDIO_ESD) { retcode=ESD_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(ALSA) if(audiotype == AUDIO_ALSA) { retcode=ALSA_FPX_SoundOutput_Latency(ptr); return retcode; } #endif #if defined(OSS) if(audiotype == AUDIO_OSS) { retcode=OSS_FPX_SoundOutput_Latency(ptr); return retcode; } #endif return 0; } #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) void *FPX_Init(void *ptr) { #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) FPX_SoundOutput_Detect(); #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) if ( !ptr ) return 0; // // Setup imported functions // struct FPI_Functions *fpi_functions = (struct FPI_Functions *)ptr; if ( fpi_functions->fpi_count >= 1 ) FPI_Mem_Alloc = fpi_functions->fpi_mem_alloc; // 1 if ( fpi_functions->fpi_count >= 2 ) FPI_Mem_Free = fpi_functions->fpi_mem_free; // 2 #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) if ( fpi_functions->fpi_count >= 3 ) FPI_SoundOutput_FillBuffer= fpi_functions->fpi_soundoutput_fillbuffer; // 3 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) // // Setup exported functions // memset(&fpx_functions, 0, sizeof(fpx_functions)); fpx_functions.fpx_shutdown = FPX_Shutdown; // 1 #if defined(OPENSSL) || defined(GNUTLS) fpx_functions.fpx_sslsocket_create = FPX_SSLSocket_Create; // 2 fpx_functions.fpx_sslsocket_destroy = FPX_SSLSocket_Destroy; // 3 fpx_functions.fpx_sslsocket_connect = FPX_SSLSocket_Connect; // 4 fpx_functions.fpx_sslsocket_receive = FPX_SSLSocket_Receive; // 5 fpx_functions.fpx_sslsocket_send = FPX_SSLSocket_Send; // 6 #endif // defined(OPENSSL) || defined(GNUTLS) #if defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) fpx_functions.fpx_soundoutput_open = FPX_SoundOutput_Open; // 7 fpx_functions.fpx_soundoutput_close = FPX_SoundOutput_Close; // 8 fpx_functions.fpx_soundoutput_latency = FPX_SoundOutput_Latency; // 9 #endif // defined(ALSA) || defined(OSS) || defined(ESD) || defined(PULSEAUDIO) #ifdef V4L1 fpx_functions.fpx_videoinput_open = FPX_VideoInput_Open; // 10 fpx_functions.fpx_videoinput_close = FPX_VideoInput_Close; // 11 fpx_functions.fpx_videoinput_getframe = FPX_VideoInput_GetFrame; // 12 #endif // V4L1 fpx_functions.fpx_count = 14; #ifdef OPENSSL SSL_library_init(); #elif defined(GNUTLS) gnutls_global_init(); #endif // GNUTLS return (void *)&fpx_functions; } static void FPX_Shutdown() { #ifdef OPENSSL #elif defined(GNUTLS) gnutls_global_deinit(); #endif // GNUTLS } // // SSL support functions // #ifdef OPENSSL struct SSL_Instance { SSL *ssl; SSL_CTX *sslCtx; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); fprintf(stderr,"AAAAAAAAAA\n"); if ( ( instance->sslCtx = SSL_CTX_new( TLSv1_client_method() ) ) == 0 ) goto fail; if ( ( instance->ssl = SSL_new(instance->sslCtx) ) == 0 ) goto fail; if ( SSL_set_fd(instance->ssl, socket_fd) < 0 ) goto fail; return (void *)instance; fail: if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; if ( instance->ssl ) { SSL_shutdown(instance->ssl); } if ( instance->sslCtx ) { SSL_CTX_free(instance->sslCtx); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_connect(instance->ssl); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_read(instance->ssl, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return SSL_write(instance->ssl, buffer, n_bytes); } #elif defined(GNUTLS) struct SSL_Instance { gnutls_session_t session; gnutls_anon_client_credentials_t anoncred; }; static void *FPX_SSLSocket_Create(int socket_fd) // return = instance pointer { const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 }; struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); memset(instance,0,sizeof(struct SSL_Instance)); if ( gnutls_anon_allocate_client_credentials(&instance->anoncred) < 0 ) goto fail; if ( gnutls_init(&instance->session, GNUTLS_CLIENT) < 0 ) goto fail; if ( gnutls_set_default_priority(instance->session) < 0 ) goto fail; if ( gnutls_kx_set_priority(instance->session, kx_prio) < 0 ) goto fail; if ( gnutls_credentials_set(instance->session, GNUTLS_CRD_ANON, instance->anoncred) < 0 ) goto fail; gnutls_transport_set_ptr(instance->session, (gnutls_transport_ptr_t)socket_fd); return (void *)instance; fail: if ( instance->session ) { gnutls_deinit(instance->session); } if ( instance->anoncred ) { gnutls_anon_free_client_credentials(instance->anoncred); } if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Destroy(void *ptr) // ptr = instance pointer // return = 0 on sucess, < 0 on error { struct SSL_Instance *instance = (struct SSL_Instance *)FPI_Mem_Alloc(sizeof(struct SSL_Instance)); gnutls_bye(instance->session, GNUTLS_SHUT_RDWR); gnutls_deinit(instance->session); gnutls_anon_free_client_credentials(instance->anoncred); if (FPI_Mem_Free) FPI_Mem_Free(instance); return 0; } static int FPX_SSLSocket_Connect(void *ptr) // ptr = instance pointer // socket_fd = BSD socket fd to be associated with SSL connection // return = 0 on sucess, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_handshake(instance->session); } static int FPX_SSLSocket_Receive(void *ptr, char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to place received data into // n_bytes = length of buffer in bytes // return = actual bytes received, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_recv(instance->session, buffer, n_bytes); } static int FPX_SSLSocket_Send(void *ptr, const char *buffer, int n_bytes) // ptr = instance pointer // buffer = raw buffer to be sent // n_bytes = length of input buffer in bytes // return = actual bytes sent, < 0 on error // // Flash Player will use errno to obtain current status { struct SSL_Instance *instance = (struct SSL_Instance *)ptr; return gnutls_record_send(instance->session, buffer, n_bytes); } #endif // GNUTLS // // Sound support functions // #ifdef ALSA struct ALSA_SoundOutput_Instance { snd_pcm_t * handle; snd_async_handler_t * async_handler; sem_t semaphore; pthread_t thread; char * buffer; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; snd_pcm_sframes_t buffer_pos; char * buffer_ptr; }; static void *alsa_thread(void *ptr) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; snd_pcm_sframes_t avail = 0; int result = 0; int err = 0; int state = 0; for( ; ; ) { err = sem_wait(&instance->semaphore); if ( !instance->handle ) { pthread_exit(0); return 0; } if ( err < 0 ) { usleep(1); continue; } do { if ( instance->buffer_pos <= 0 ) { FPI_SoundOutput_FillBuffer(ptr, instance->buffer, snd_pcm_frames_to_bytes(instance->handle, instance->period_size)); instance->buffer_pos = instance->period_size; instance->buffer_ptr = instance->buffer; } do { state = snd_pcm_state(instance->handle); if(state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { snd_pcm_prepare(instance->handle); } result = snd_pcm_writei(instance->handle, instance->buffer_ptr, instance->buffer_pos); if( result <= 0 ) { switch( result ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } else { instance->buffer_pos -= result; instance->buffer_ptr += snd_pcm_frames_to_bytes(instance->handle, result); } } while (instance->buffer_pos); avail = snd_pcm_avail_update(instance->handle); if( avail < 0 ) { switch( avail ) { case -EPIPE: { snd_pcm_prepare(instance->handle); } break; case -ESTRPIPE: { err = snd_pcm_resume(instance->handle); if ( err < 0 ) { snd_pcm_prepare(instance->handle); } } break; } break; } } while(avail >= instance->period_size); } } static void alsa_callback(snd_async_handler_t *ahandler) { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)snd_async_handler_get_callback_private(ahandler); // signal mixer thread sem_post(&instance->semaphore); } static void *ALSA_FPX_SoundOutput_Open() // return = instance pointer { struct ALSA_SoundOutput_Instance *instance = 0; snd_pcm_hw_params_t *hwparams = 0; snd_pcm_sw_params_t *swparams = 0; snd_pcm_format_t pcm_format; unsigned int buffer_time = 500000; unsigned int period_time = 20000; unsigned int actual_rate; snd_pcm_uframes_t size; int direction; void *retVal = 0; int err = 0; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = FPI_Mem_Alloc(sizeof(struct ALSA_SoundOutput_Instance)); memset(instance,0,sizeof(struct ALSA_SoundOutput_Instance)); if ( ( err = snd_pcm_open(&instance->handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { if ( ( err = snd_pcm_open(&instance->handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) ) < 0) { goto fail; } } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if (snd_pcm_hw_params_any(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_hw_params_set_access(instance->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) goto fail; pcm_format = SND_PCM_FORMAT_S16_LE; if (snd_pcm_hw_params_set_format(instance->handle, hwparams, pcm_format) < 0) goto fail; if (snd_pcm_hw_params_set_channels(instance->handle, hwparams, 2) < 0) goto fail; actual_rate = 44100; if (snd_pcm_hw_params_set_rate_near(instance->handle, hwparams, &actual_rate, 0) < 0) goto fail; if (actual_rate != 44100) goto fail; if (snd_pcm_hw_params_set_buffer_time_near(instance->handle, hwparams, &buffer_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_buffer_size(hwparams, &size) < 0) goto fail; instance->buffer_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params_set_period_time_near(instance->handle, hwparams, &period_time, &direction) < 0) goto fail; if (snd_pcm_hw_params_get_period_size(hwparams, &size, &direction) < 0) goto fail; instance->period_size = (snd_pcm_sframes_t)size; if (snd_pcm_hw_params(instance->handle, hwparams) < 0) goto fail; if (snd_pcm_sw_params_current(instance->handle, swparams) < 0) goto fail; if (snd_pcm_sw_params_set_start_threshold(instance->handle, swparams, ((instance->buffer_size-1) / instance->period_size) * instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_stop_threshold(instance->handle, swparams, ~0U) < 0) goto fail; if (snd_pcm_sw_params_set_avail_min(instance->handle, swparams, instance->period_size) < 0) goto fail; if (snd_pcm_sw_params_set_xfer_align(instance->handle, swparams, 1) < 0) goto fail; if (snd_pcm_sw_params(instance->handle, swparams) < 0) goto fail; if (snd_async_add_pcm_handler(&instance->async_handler, instance->handle, &alsa_callback, instance) < 0) goto fail; if ( ( instance->buffer = FPI_Mem_Alloc(instance->buffer_size * 2 * 2 * 2) ) == 0 ) goto fail; if ( pthread_create(&instance->thread, 0, alsa_thread, instance) < 0 ) goto fail; sem_post(&instance->semaphore); return instance; fail: if ( instance ) { if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ALSA_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; void *retVal = 0; if ( instance->handle ) { snd_pcm_drop(instance->handle); snd_pcm_close(instance->handle); instance->handle = 0; } if ( instance->thread ) { sem_post(&instance->semaphore); sem_destroy(&instance->semaphore); pthread_join(instance->thread,&retVal); } if ( instance->buffer ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance->buffer); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int ALSA_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ALSA_SoundOutput_Instance *instance = (struct ALSA_SoundOutput_Instance *)ptr; if ( instance->handle ) { snd_pcm_sframes_t delay = 0; snd_pcm_delay(instance->handle, &delay); if ( snd_pcm_state(instance->handle) == SND_PCM_STATE_RUNNING && delay > 0 ) { return delay; } else { return 0; } } return -1; } #endif #if defined(OSS) struct OSS_SoundOutput_Instance { int oss_fd; pthread_t thread; int signal; }; static void *oss_thread(void *ptr) { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->oss_fd, buffer, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *OSS_FPX_SoundOutput_Open() // return = instance pointer { struct OSS_SoundOutput_Instance *instance = 0; int format = AFMT_S16_LE; int stereo = 1; int speed = 44100; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct OSS_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct OSS_SoundOutput_Instance)); memset(instance,0,sizeof(struct OSS_SoundOutput_Instance)); if ( ( instance->oss_fd = open("/dev/dsp",O_WRONLY) ) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SETFMT, &format) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0 ) goto fail; if ( ioctl(instance->oss_fd, SNDCTL_DSP_SPEED, &speed) < 0 ) goto fail; if ( pthread_create(&instance->thread, 0, oss_thread, instance) < 0 ) goto fail; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int OSS_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->oss_fd ) { ioctl(instance->oss_fd, SNDCTL_DSP_RESET, 0); } if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->oss_fd ) { close(instance->oss_fd); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int OSS_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct OSS_SoundOutput_Instance *instance = (struct OSS_SoundOutput_Instance *)ptr; if ( instance->oss_fd ) { int value = 0; if ( ( value = ioctl(instance->oss_fd,SNDCTL_DSP_GETODELAY,&value) ) == 0 ) { return value / 4; } return 0; } return -1; } #endif #if defined(ESD) struct ESD_SoundOutput_Instance { int esd_sock; pthread_t thread; int signal; }; static void *esd_thread(void *ptr) { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; char buffer[4096]; int len = 0; int written = 0; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; while ( len ) { written = write(instance->esd_sock, buffer+4096-len, len); if ( written >= 0 ) { len -= written; } if ( instance->signal ) { pthread_exit(0); } if ( written < 0 ) { usleep(100); } } } } static void *ESD_FPX_SoundOutput_Open() // return = instance pointer { struct ESD_SoundOutput_Instance *instance = 0; int rate = ESD_DEFAULT_RATE; int bits = ESD_BITS16, channels = ESD_STEREO; int mode = ESD_STREAM, func = ESD_PLAY ; esd_format_t format = 0; char *host = NULL; char *name = NULL; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; format = bits | channels | mode | func; instance = (struct ESD_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct ESD_SoundOutput_Instance)); memset(instance,0,sizeof(struct ESD_SoundOutput_Instance)); instance->esd_sock=-1; if(audiodebug) fprintf( stderr, "opening socket, format = 0x%08x at %d Hz\n",format, rate ); if ( ( instance->esd_sock = FPX_esd_play_stream_fallback( format, rate, host, name )) <= 0 ) goto fail; if ( pthread_create(&instance->thread, 0, esd_thread, instance) < 0 ) goto fail; return instance; fail: if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int ESD_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->esd_sock ) { close(instance->esd_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int ESD_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { /* JMD: this doesn't work. I think it's due to the handling of signals in esdlib.c ... It just *hangs* via network... struct ESD_SoundOutput_Instance *instance = (struct ESD_SoundOutput_Instance *)ptr; if ( instance->esd_sock ) { return (esd_get_latency(instance->esd_sock)); } */ return -1; } #endif #if defined(PULSEAUDIO) struct PULSE_SoundOutput_Instance { pa_simple *pa_sock; pthread_t thread; int signal; }; static void *pa_thread(void *ptr) { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; char buffer[4096]; size_t len = 0; int error; for(;;) { FPI_SoundOutput_FillBuffer(ptr,buffer,4096); len = 4096; if (FPX_pa_simple_write(instance->pa_sock, buffer, len, &error) < 0) { if(audiodebug) fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", FPX_pa_strerror(error)); usleep(100); } if ( instance->signal ) { pthread_exit(0); } } } static void *PULSEAUDIO_FPX_SoundOutput_Open() // return = instance pointer { struct PULSE_SoundOutput_Instance *instance = 0; int error; if(audiodebug) fprintf( stderr, "Called FPX_SoundOutput_Open\n"); /* The Sample format to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; if ( !FPI_SoundOutput_FillBuffer ) goto fail; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct PULSE_SoundOutput_Instance *)FPI_Mem_Alloc(sizeof(struct PULSE_SoundOutput_Instance)); memset(instance,0,sizeof(struct PULSE_SoundOutput_Instance)); if ( ( instance->pa_sock = FPX_pa_simple_new(NULL, "flashplayer", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error)) <= 0 ) goto fail; if(audiodebug) fprintf( stderr, "Opened Pulse\n"); if ( pthread_create(&instance->thread, 0, pa_thread, instance) < 0 ) goto fail; return instance; fail: if(audiodebug) fprintf( stderr, "FAILED TO OPEN PULSEAUDIO!\n"); if ( instance ) { if ( FPI_Mem_Free ) FPI_Mem_Free(instance); } return 0; } static int PULSEAUDIO_FPX_SoundOutput_Close(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; void *retVal = 0; int error; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->pa_sock ) { FPX_pa_simple_drain(instance->pa_sock, &error); FPX_pa_simple_free(instance->pa_sock); } if ( FPI_Mem_Free ) FPI_Mem_Free(instance); return 0; } static int PULSEAUDIO_FPX_SoundOutput_Latency(void *ptr) // ptr = instance pointer // return = 0 on success, < 0 on error { pa_usec_t latencytime=0; float latencysamples=0.0; int latency=0; int error; struct PULSE_SoundOutput_Instance *instance = (struct PULSE_SoundOutput_Instance *)ptr; if ( instance->pa_sock ) { latencytime = FPX_pa_simple_get_latency(instance->pa_sock, &error); } if(pulsedebug) fprintf(stderr, "\nLatency: %0.0f usec \n", (float)latencytime); /* Max bytes in one second: sample_rate*num_of_channels*sample_size_in_bytes 44100 * 2 (stereo) * 2 (16 bit samples) Magic number = 176400 Max frames in one second: sample_rate: 44100 Magic number = 44100 Now, convert pulse's latency time to number of bytes as required by FlashPlayer Latency = magic number * latencytime / 1000000 (for microseconds) */ latencysamples= 44100 * latencytime / 1000000; latency=(int)latencysamples; if(pulsedebug) fprintf(stderr, "\nLatency: %d samples\n", latency); return latency; return -1; } #endif // defined(ALSA/OSS/ESD/PULSEAUDIO) #ifdef V4L1 struct VideoOutput_Instance { int v4l_fd; pthread_t thread; int signal; char * buffer[2]; int buffercurrent; int buffersize; struct video_window window; struct video_picture picture; }; static void *v4l_thread(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int result; int status; for(;;) { result = read(instance->v4l_fd, instance->buffer[instance->buffercurrent], instance->buffersize); if(result > 0) { } if ( result < 0 ) { usleep(10000); } if ( instance->signal ) { status = 0; ioctl(instance->v4l_fd, VIDIOCCAPTURE, &status); pthread_exit(0); } } } static void *FPX_VideoInput_Open() { struct VideoOutput_Instance *instance = 0; if ( !FPI_Mem_Alloc ) goto fail; instance = (struct VideoOutput_Instance *)FPI_Mem_Alloc(sizeof(struct VideoOutput_Instance)); memset(instance,0,sizeof(struct VideoOutput_Instance)); if ( ( instance->v4l_fd = open("/dev/video", O_RDONLY) ) < 0 ) goto fail; if ( ioctl(instance->v4l_fd, VIDIOCGPICT, &instance->picture) < 0 ) goto fail; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: break; case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_YUV422P: case VIDEO_PALETTE_YUV411P: case VIDEO_PALETTE_YUV410P: case VIDEO_PALETTE_GREY: case VIDEO_PALETTE_HI240: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB32: case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_YUV422: case VIDEO_PALETTE_YUYV: case VIDEO_PALETTE_UYVY: case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV411: case VIDEO_PALETTE_RAW: default: goto fail; } if( ioctl(instance->v4l_fd, VIDIOCGWIN, &instance->window) < 0 ) goto fail; instance->buffer[0] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); instance->buffer[1] = FPI_Mem_Alloc(instance->window.width * instance->window.height * 2); if ( pthread_create(&instance->thread, 0, v4l_thread, instance) < 0 ) goto fail; return instance; fail: if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_Close(void *ptr) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; void *retVal = 0; instance->signal = 1; if ( instance->thread ) { pthread_join(instance->thread,&retVal); } if ( instance->v4l_fd ) { close(instance->v4l_fd); } if ( FPI_Mem_Free ) { if ( instance->buffer[0] ) { FPI_Mem_Free(instance->buffer[0]); } if ( instance->buffer[1] ) { FPI_Mem_Free(instance->buffer[1]); } FPI_Mem_Free(instance); } return 0; } static int FPX_VideoInput_GetFrame(void *ptr, char *data, int width, int height, int pitch_n_bytes) { struct VideoOutput_Instance *instance = (struct VideoOutput_Instance *)ptr; int ix, iy, ox, oy, ow, oh, dx, dy, Y, U, V, R, G, B; unsigned char *y, *u, *v; switch(instance->picture.palette) { case VIDEO_PALETTE_YUV420P: { ow = instance->window.width; oh = instance->window.height; dx = (ow<<16) / width; dy = (oh<<16) / height; y = (unsigned char *)instance->buffer[instance->buffercurrent^1]; u = y + ow * oh; v = u + ow * oh / 4; oy = 0; for ( iy = 0; iy < height; iy++ ) { ox = 0; for ( ix = 0; ix < width; ix++ ) { Y = ( 149 * ((int)(y[(oy>>16)*(ow )+(ox>>16)]) - 16) ) / 2; U = (int)(u[(oy>>17)*(ow/2)+(ox>>17)]) - 128; V = (int)(v[(oy>>17)*(ow/2)+(ox>>17)]) - 128; R = (Y + V * 102 ) / 64; G = (Y - V * 52 - U * 25 ) / 64; B = (Y + U * 129 ) / 64; R = R < 0 ? 0 : ( R > 255 ? 255 : R ); G = G < 0 ? 0 : ( G > 255 ? 255 : G ); B = B < 0 ? 0 : ( B > 255 ? 255 : B ); data[ix*3+0] = R; data[ix*3+1] = G; data[ix*3+2] = B; ox += dx; } oy += dy; data += pitch_n_bytes; } } break; default: goto fail; } instance->buffercurrent ^= 1; return 0; fail: return -1; } #endif // V4L1