void AudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { audio_output_t * p_aout = (audio_output_t *)inUserData; aout_buffer_t * p_buffer = NULL; if (p_aout) { struct aout_sys_t * p_sys = p_aout->sys; aout_packet_t * packet = &p_sys->packet; if (packet) { vlc_mutex_lock( &packet->lock ); p_buffer = aout_FifoPop2( &packet->fifo ); vlc_mutex_unlock( &packet->lock ); } } if ( p_buffer != NULL ) { vlc_memcpy( inBuffer->mAudioData, p_buffer->p_buffer, p_buffer->i_buffer ); inBuffer->mAudioDataByteSize = p_buffer->i_buffer; aout_BufferFree( p_buffer ); } else { vlc_memset( inBuffer->mAudioData, 0, inBuffer->mAudioDataBytesCapacity ); inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity; } AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); }
/***************************************************************************** * Thread: thread used to DMA the data to the device *****************************************************************************/ static void* Thread( vlc_object_t *p_this ) { aout_instance_t * p_aout = (aout_instance_t*)p_this; aout_buffer_t * p_buffer; struct aout_sys_t * p_sys = p_aout->output.p_sys; PCMAudioPlayer * pPlayer = p_sys->pPlayer; int canc = vlc_savecancel (); while( vlc_object_alive (p_aout) ) { pPlayer->WaitForBuffer(); vlc_mutex_lock( &p_aout->output_fifo_lock ); p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); vlc_mutex_unlock( &p_aout->output_fifo_lock ); #define i p_sys->nNextBufferIndex if( p_buffer == NULL ) { vlc_memset( p_aout, p_sys->ppBuffers[ i ], 0, p_sys->nBufferSize ); } else { InterleaveS16( (int16_t *)p_buffer->p_buffer, (int16_t *)p_sys->ppBuffers[ i ] ); aout_BufferFree( p_buffer ); } if( !pPlayer->QueueBuffer( (s16 *)p_sys->ppBuffers[ i ], p_sys->nBufferSize / 2 ) ) { msg_Err( p_aout, "QueueBuffer failed" ); } i = (i + 1) % p_sys->nBuffers; #undef i } vlc_restorecancel (canc); return NULL; }
/* This routine will be called by the PortAudio engine when audio is needed. * It may called at interrupt level on some machines so don't do anything * that could mess up the system like calling malloc() or free(). */ static int paCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *paDate, PaStreamCallbackFlags statusFlags, void *p_cookie ) { VLC_UNUSED( inputBuffer ); VLC_UNUSED( statusFlags ); struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie; aout_instance_t *p_aout = p_sys->p_aout; aout_buffer_t *p_buffer; mtime_t out_date; out_date = mdate() + (mtime_t) ( 1000000 * ( paDate->outputBufferDacTime - paDate->currentTime ) ); p_buffer = aout_OutputNextBuffer( p_aout, out_date, true ); if ( p_buffer != NULL ) { if( p_sys->b_chan_reorder ) { /* Do the channel reordering here */ aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes, p_sys->i_channels, p_sys->pi_chan_table, p_sys->i_bits_per_sample ); } vlc_memcpy( outputBuffer, p_buffer->p_buffer, framesPerBuffer * p_sys->i_sample_size ); /* aout_BufferFree may be dangereous here, but then so is * aout_OutputNextBuffer (calls aout_BufferFree internally). * one solution would be to link the no longer useful buffers * in a second fifo (in aout_OutputNextBuffer too) and to * wait until we are in Play to do the actual free. */ aout_BufferFree( p_buffer ); } else /* Audio output buffer shortage -> stop the fill process and wait */ { vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size ); } return 0; }
/***************************************************************************** * DoWork: convert a buffer *****************************************************************************/ static block_t *DoWork( filter_t * p_filter, block_t *p_in_buf ) { /* AC3 is natively big endian. Most SPDIF devices have the native * endianness of the computer system. * On Mac OS X however, little endian devices are also common. */ static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 }; static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x01 }; uint16_t i_frame_size = p_in_buf->i_buffer / 2; uint8_t * p_in = p_in_buf->p_buffer; block_t *p_out_buf = filter_NewAudioBuffer( p_filter, AOUT_SPDIF_SIZE ); if( !p_out_buf ) goto out; uint8_t * p_out = p_out_buf->p_buffer; /* Copy the S/PDIF headers. */ if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) { vlc_memcpy( p_out, p_sync_be, 6 ); p_out[4] = p_in[5] & 0x7; /* bsmod */ SetWBE( p_out + 6, i_frame_size << 4 ); vlc_memcpy( &p_out[8], p_in, i_frame_size * 2 ); } else { vlc_memcpy( p_out, p_sync_le, 6 ); p_out[5] = p_in[5] & 0x7; /* bsmod */ SetWLE( p_out + 6, i_frame_size << 4 ); swab( p_in, &p_out[8], i_frame_size * 2 ); } vlc_memset( p_out + 8 + i_frame_size * 2, 0, AOUT_SPDIF_SIZE - i_frame_size * 2 - 8 ); p_out_buf->i_dts = p_in_buf->i_dts; p_out_buf->i_pts = p_in_buf->i_pts; p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; p_out_buf->i_buffer = AOUT_SPDIF_SIZE; out: block_Release( p_in_buf ); return p_out_buf; }
void AudioQueueCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { aout_instance_t * p_aout = (aout_instance_t *)inUserData; aout_buffer_t * p_buffer = NULL; if (p_aout) { vlc_mutex_lock( &p_aout->output_fifo_lock ); p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); vlc_mutex_unlock( &p_aout->output_fifo_lock ); } if ( p_buffer != NULL ) { vlc_memcpy( inBuffer->mAudioData, p_buffer->p_buffer, p_buffer->i_buffer ); inBuffer->mAudioDataByteSize = p_buffer->i_buffer; aout_BufferFree( p_buffer ); } else { vlc_memset( inBuffer->mAudioData, 0, inBuffer->mAudioDataBytesCapacity ); inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity; } AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); }
/***************************************************************************** * SDLCallback: what to do once SDL has played sound samples *****************************************************************************/ static void SDLCallback( void * _p_aout, uint8_t * p_stream, int i_len ) { aout_instance_t * p_aout = (aout_instance_t *)_p_aout; aout_buffer_t * p_buffer; /* SDL is unable to call us at regular times, or tell us its current * hardware latency, or the buffer state. So we just pop data and throw * it at SDL's face. Nah. */ vlc_mutex_lock( &p_aout->output_fifo_lock ); p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo ); vlc_mutex_unlock( &p_aout->output_fifo_lock ); if ( p_buffer != NULL ) { vlc_memcpy( p_stream, p_buffer->p_buffer, i_len ); aout_BufferFree( p_buffer ); } else { vlc_memset( p_stream, 0, i_len ); } }
/* This routine will be called by the PortAudio engine when audio is needed. * It may called at interrupt level on some machines so don't do anything * that could mess up the system like calling malloc() or free(). */ static int paCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *paDate, PaStreamCallbackFlags statusFlags, void *p_cookie ) { VLC_UNUSED( inputBuffer ); VLC_UNUSED( statusFlags ); struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie; audio_output_t *p_aout = p_sys->p_aout; aout_buffer_t *p_buffer; mtime_t out_date; out_date = mdate() + (mtime_t) ( 1000000 * ( paDate->outputBufferDacTime - paDate->currentTime ) ); p_buffer = aout_PacketNext( p_aout, out_date ); if ( p_buffer != NULL ) { if( p_sys->b_chan_reorder ) { /* Do the channel reordering here */ aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer, p_sys->i_channels, p_sys->pi_chan_table, p_sys->i_bits_per_sample ); } vlc_memcpy( outputBuffer, p_buffer->p_buffer, framesPerBuffer * p_sys->i_sample_size ); aout_BufferFree( p_buffer ); } else /* Audio output buffer shortage -> stop the fill process and wait */ { vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size ); } return 0; }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i_index; double f_angle; mtime_t new_date = mdate(); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } p_filter->p_sys->f_angle += (new_date - p_filter->p_sys->last_date) / 200000.0; p_filter->p_sys->last_date = new_date; f_angle = p_filter->p_sys->f_angle; for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { int i_line, i_num_lines, i_visible_pitch, i_pixel_pitch, i_offset, i_visible_pixels; uint8_t black_pixel; uint8_t *p_in, *p_out; p_in = p_pic->p[i_index].p_pixels; p_out = p_outpic->p[i_index].p_pixels; i_num_lines = p_pic->p[i_index].i_visible_lines; i_visible_pitch = p_pic->p[i_index].i_visible_pitch; i_pixel_pitch = p_pic->p[i_index].i_pixel_pitch; switch( p_filter->fmt_in.video.i_chroma ) { CASE_PACKED_YUV_422 // Quick hack to fix u/v inversion occuring with 2 byte pixel pitch i_pixel_pitch *= 2; break; } i_visible_pixels = i_visible_pitch/i_pixel_pitch; black_pixel = ( p_pic->i_planes > 1 && i_index == Y_PLANE ) ? 0x00 : 0x80; /* Ok, we do 3 times the sin() calculation for each line. So what ? */ for( i_line = 0 ; i_line < i_num_lines ; i_line++ ) { /* Calculate today's offset, don't go above 1/20th of the screen */ i_offset = (int)( (double)(i_visible_pixels) * sin( f_angle + 10.0 * (double)i_line / (double)i_num_lines ) / 20.0 )*i_pixel_pitch; if( i_offset ) { if( i_offset < 0 ) { vlc_memcpy( p_out, p_in - i_offset, i_visible_pitch + i_offset ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; vlc_memset( p_out + i_offset, black_pixel, -i_offset ); } else { vlc_memcpy( p_out + i_offset, p_in, i_visible_pitch - i_offset ); vlc_memset( p_out, black_pixel, i_offset ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } else { vlc_memcpy( p_out, p_in, i_visible_pitch ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; unsigned int w, h; int x,y; uint8_t u,v; picture_t *p_converted; video_format_t fmt_out; memset( &fmt_out, 0, sizeof(video_format_t) ); fmt_out.p_palette = NULL; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } if( !p_filter->p_sys->p_image ) p_filter->p_sys->p_image = image_HandlerCreate( p_filter ); /* chrominance */ u = p_filter->p_sys->u; v = p_filter->p_sys->v; for( y = 0; y<p_outpic->p[U_PLANE].i_lines; y++) { vlc_memset( p_outpic->p[U_PLANE].p_pixels+y*p_outpic->p[U_PLANE].i_pitch, u, p_outpic->p[U_PLANE].i_pitch ); vlc_memset( p_outpic->p[V_PLANE].p_pixels+y*p_outpic->p[V_PLANE].i_pitch, v, p_outpic->p[V_PLANE].i_pitch ); if( v == 0 && u != 0 ) u --; else if( u == 0xff ) v --; else if( v == 0xff ) u ++; else if( u == 0 ) v ++; } /* luminance */ vlc_memcpy( p_outpic->p[Y_PLANE].p_pixels, p_pic->p[Y_PLANE].p_pixels, p_outpic->p[Y_PLANE].i_lines * p_outpic->p[Y_PLANE].i_pitch ); /* image visualization */ fmt_out = p_filter->fmt_out.video; fmt_out.i_width = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150; fmt_out.i_height = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150; p_converted = image_Convert( p_filter->p_sys->p_image, p_pic, &(p_pic->format), &fmt_out ); if( p_converted ) { #define copyimage( plane, b ) \ for( y=0; y<p_converted->p[plane].i_visible_lines; y++) { \ for( x=0; x<p_converted->p[plane].i_visible_pitch; x++) { \ int nx, ny; \ if( p_filter->p_sys->yinc == 1 ) \ ny= y; \ else \ ny = p_converted->p[plane].i_visible_lines-y; \ if( p_filter->p_sys->xinc == 1 ) \ nx = x; \ else \ nx = p_converted->p[plane].i_visible_pitch-x; \ p_outpic->p[plane].p_pixels[(p_filter->p_sys->x*b+nx)+(ny+p_filter->p_sys->y*b)*p_outpic->p[plane].i_pitch ] = p_converted->p[plane].p_pixels[y*p_converted->p[plane].i_pitch+x]; \ } } copyimage( Y_PLANE, 2 ); copyimage( U_PLANE, 1 ); copyimage( V_PLANE, 1 ); #undef copyimage picture_Release( p_converted ); } else { msg_Err( p_filter, "Image scaling failed miserably." ); } p_filter->p_sys->x += p_filter->p_sys->xinc; p_filter->p_sys->y += p_filter->p_sys->yinc; p_filter->p_sys->scale += p_filter->p_sys->scaleinc; if( p_filter->p_sys->scale >= 50 ) p_filter->p_sys->scaleinc = -1; if( p_filter->p_sys->scale <= 1 ) p_filter->p_sys->scaleinc = 1; w = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150; h = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150; if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width ) p_filter->p_sys->xinc = -1; if( p_filter->p_sys->x <= 0 ) p_filter->p_sys->xinc = 1; if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width ) p_filter->p_sys->x = (p_filter->fmt_out.video.i_width-w)/2; if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height ) p_filter->p_sys->y = (p_filter->fmt_out.video.i_height-h)/2; if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height ) p_filter->p_sys->yinc = -1; if( p_filter->p_sys->y <= 0 ) p_filter->p_sys->yinc = 1; for( y = 0; y< 16; y++ ) { if( p_filter->p_sys->v == 0 && p_filter->p_sys->u != 0 ) p_filter->p_sys->u -= 1; else if( p_filter->p_sys->u == 0xff ) p_filter->p_sys->v -= 1; else if( p_filter->p_sys->v == 0xff ) p_filter->p_sys->u += 1; else if( p_filter->p_sys->u == 0 ) p_filter->p_sys->v += 1; } return CopyInfoAndRelease( p_outpic, p_pic ); }
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; int i,j; int i_lines = p_pic->p[ A_PLANE ].i_lines; int i_pitch = p_pic->p[ A_PLANE ].i_pitch; uint8_t *p_a = p_pic->p[ A_PLANE ].p_pixels; uint8_t *p_at; uint8_t *p_u = p_pic->p[ U_PLANE ].p_pixels; uint8_t *p_v = p_pic->p[ V_PLANE ].p_pixels; uint8_t umin, umax, vmin, vmax; if( p_pic->format.i_chroma != VLC_CODEC_YUVA ) { msg_Err( p_filter, "Unsupported input chroma \"%4.4s\". " "Bluescreen can only use \"YUVA\".", (char*)&p_pic->format.i_chroma ); return NULL; } p_sys->p_at = xrealloc( p_sys->p_at, i_lines * i_pitch * sizeof( uint8_t ) ); p_at = p_sys->p_at; vlc_mutex_lock( &p_sys->lock ); umin = p_sys->i_u - p_sys->i_ut >= 0x00 ? p_sys->i_u - p_sys->i_ut : 0x00; umax = p_sys->i_u + p_sys->i_ut <= 0xff ? p_sys->i_u + p_sys->i_ut : 0xff; vmin = p_sys->i_v - p_sys->i_vt >= 0x00 ? p_sys->i_v - p_sys->i_vt : 0x00; vmax = p_sys->i_v + p_sys->i_vt <= 0xff ? p_sys->i_v + p_sys->i_vt : 0xff; vlc_mutex_unlock( &p_sys->lock ); for( i = 0; i < i_lines*i_pitch; i++ ) { if( p_u[i] < umax && p_u[i] > umin && p_v[i] < vmax && p_v[i] > vmin ) { p_at[i] = 0x00; } else { p_at[i] = 0xff; } } /* Gaussian convolution to make it look cleaner */ vlc_memset( p_a, 0, 2 * i_pitch ); for( i = 2; i < i_lines - 2; i++ ) { p_a[i*i_pitch] = 0x00; p_a[i*i_pitch+1] = 0x00; for( j = 2; j < i_pitch - 2; j ++ ) { p_a[i*i_pitch+j] = (uint8_t)(( /* 2 rows up */ ( p_at[(i-2)*i_pitch+j-2]<<1 ) + ( p_at[(i-2)*i_pitch+j-1]<<2 ) + ( p_at[(i-2)*i_pitch+j]<<2 ) + ( p_at[(i-2)*i_pitch+j+1]<<2 ) + ( p_at[(i-2)*i_pitch+j+2]<<1 ) /* 1 row up */ + ( p_at[(i-1)*i_pitch+j-2]<<2 ) + ( p_at[(i-1)*i_pitch+j-1]<<3 ) + ( p_at[(i-1)*i_pitch+j]*12 ) + ( p_at[(i-1)*i_pitch+j+1]<<3 ) + ( p_at[(i-1)*i_pitch+j+2]<<2 ) /* */ + ( p_at[i*i_pitch+j-2]<<2 ) + ( p_at[i*i_pitch+j-1]*12 ) + ( p_at[i*i_pitch+j]<<4 ) + ( p_at[i*i_pitch+j+1]*12 ) + ( p_at[i*i_pitch+j+2]<<2 ) /* 1 row down */ + ( p_at[(i+1)*i_pitch+j-2]<<2 ) + ( p_at[(i+1)*i_pitch+j-1]<<3 ) + ( p_at[(i+1)*i_pitch+j]*12 ) + ( p_at[(i+1)*i_pitch+j+1]<<3 ) + ( p_at[(i+1)*i_pitch+j+2]<<2 ) /* 2 rows down */ + ( p_at[(i+2)*i_pitch+j-2]<<1 ) + ( p_at[(i+2)*i_pitch+j-1]<<2 ) + ( p_at[(i+2)*i_pitch+j]<<2 ) + ( p_at[(i+2)*i_pitch+j+1]<<2 ) + ( p_at[(i+2)*i_pitch+j+2]<<1 ) )/152); if( p_a[i*i_pitch+j] < 0xbf ) p_a[i*i_pitch+j] = 0x00; } } return p_pic; }
/** * Rearranges audio blocks in correct number of samples. * @note (FIXME) This is left here for historical reasons. It belongs in the * output code. Besides, this operation should be avoided if possible. */ static block_t *aout_OutputSlice (audio_output_t *p_aout) { aout_packet_t *p = aout_packet (p_aout); aout_fifo_t *p_fifo = &p->partial; const unsigned samples = p->samples; assert( samples > 0 ); vlc_assert_locked( &p->lock ); /* Retrieve the date of the next buffer. */ date_t exact_start_date = p->fifo.end_date; mtime_t start_date = date_Get( &exact_start_date ); /* See if we have enough data to prepare a new buffer for the audio output. */ aout_buffer_t *p_buffer = p_fifo->p_first; if( p_buffer == NULL ) return NULL; /* Find the earliest start date available. */ if ( start_date == VLC_TS_INVALID ) { start_date = p_buffer->i_pts; date_Set( &exact_start_date, start_date ); } /* Compute the end date for the new buffer. */ mtime_t end_date = date_Increment( &exact_start_date, samples ); /* Check that we have enough samples (TODO merge with next loop). */ for( unsigned available = 0; available < samples; ) { p_buffer = p_buffer->p_next; if( p_buffer == NULL ) return NULL; available += p_buffer->i_nb_samples; } if( AOUT_FMT_LINEAR( &p_aout->format ) ) { const unsigned framesize = p_aout->format.i_bytes_per_frame; /* Build packet with adequate number of samples */ unsigned needed = samples * framesize; p_buffer = block_Alloc( needed ); if( unlikely(p_buffer == NULL) ) /* XXX: should free input buffers */ return NULL; p_buffer->i_nb_samples = samples; for( uint8_t *p_out = p_buffer->p_buffer; needed > 0; ) { aout_buffer_t *p_inbuf = p_fifo->p_first; if( unlikely(p_inbuf == NULL) ) { msg_Err( p_aout, "packetization error" ); vlc_memset( p_out, 0, needed ); break; } const uint8_t *p_in = p_inbuf->p_buffer; size_t avail = p_inbuf->i_nb_samples * framesize; if( avail > needed ) { vlc_memcpy( p_out, p_in, needed ); p_fifo->p_first->p_buffer += needed; p_fifo->p_first->i_buffer -= needed; needed /= framesize; p_fifo->p_first->i_nb_samples -= needed; mtime_t t = needed * CLOCK_FREQ / p_aout->format.i_rate; p_fifo->p_first->i_pts += t; p_fifo->p_first->i_length -= t; break; } vlc_memcpy( p_out, p_in, avail ); needed -= avail; p_out += avail; /* Next buffer */ aout_BufferFree( aout_FifoPop( p_fifo ) ); } } else p_buffer = aout_FifoPop( p_fifo ); p_buffer->i_pts = start_date; p_buffer->i_length = end_date - start_date; return p_buffer; }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i_index; double f_angle; mtime_t new_date = mdate(); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } p_filter->p_sys->f_angle -= (p_filter->p_sys->last_date - new_date) / 100000.0; p_filter->p_sys->last_date = new_date; f_angle = p_filter->p_sys->f_angle; for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { int i_line, i_first_line, i_num_lines, i_offset, i_pixel_pitch, i_visible_pixels; uint8_t black_pixel; uint8_t *p_in, *p_out; black_pixel = ( p_pic->i_planes > 1 && i_index == Y_PLANE ) ? 0x00 : 0x80; i_num_lines = p_pic->p[i_index].i_visible_lines; i_pixel_pitch = p_pic->p[i_index].i_pixel_pitch; i_visible_pixels = p_pic->p[i_index].i_visible_pitch/p_pic->p[i_index].i_pixel_pitch; i_first_line = i_num_lines * 4 / 5; p_in = p_pic->p[i_index].p_pixels; p_out = p_outpic->p[i_index].p_pixels; for( i_line = 0 ; i_line < i_first_line ; i_line++ ) { vlc_memcpy( p_out, p_in, p_pic->p[i_index].i_visible_pitch ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } /* Ok, we do 3 times the sin() calculation for each line. So what ? */ for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ ) { /* Calculate today's offset, don't go above 1/20th of the screen */ i_offset = (int)( (double)(i_visible_pixels) * sin( f_angle + 2.0 * (double)i_line / (double)( 1 + i_line - i_first_line) ) * (double)(i_line - i_first_line) / (double)i_num_lines / 8.0 )*p_pic->p[i_index].i_pixel_pitch; if( i_offset ) { if( i_offset < 0 ) { vlc_memcpy( p_out, p_in - i_offset, p_pic->p[i_index].i_visible_pitch + i_offset ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; vlc_memset( p_out + i_offset, black_pixel, -i_offset ); } else { vlc_memcpy( p_out + i_offset, p_in, p_pic->p[i_index].i_visible_pitch - i_offset ); vlc_memset( p_out, black_pixel, i_offset ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } else { vlc_memcpy( p_out, p_in, p_pic->p[i_index].i_visible_pitch ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/**************************************************************************** * Filter: the whole thing ****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_outpic; int i_plane; int i_width, i_height, i_xcrop, i_ycrop, i_outwidth, i_outheight, i_xpadd, i_ypadd; const int p_padd_color[] = { 0x00, 0x80, 0x80, 0xff }; if( !p_pic ) return NULL; /* Request output picture */ p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) /* p_pic and p_outpic have the same chroma/number of planes but that's * about it. */ { plane_t *p_plane = p_pic->p+i_plane; plane_t *p_outplane = p_outpic->p+i_plane; uint8_t *p_in = p_plane->p_pixels; uint8_t *p_out = p_outplane->p_pixels; int i_pixel_pitch = p_plane->i_pixel_pitch; int i_padd_color = i_plane > 3 ? p_padd_color[0] : p_padd_color[i_plane]; /* These assignments assume that the first plane always has * a width and height equal to the picture's */ i_width = ( ( p_filter->fmt_in.video.i_visible_width - p_sys->i_cropleft - p_sys->i_cropright ) * p_plane->i_visible_pitch ) / p_pic->p->i_visible_pitch; i_height = ( ( p_filter->fmt_in.video.i_visible_height - p_sys->i_croptop - p_sys->i_cropbottom ) * p_plane->i_visible_lines ) / p_pic->p->i_visible_lines; i_xcrop = ( p_sys->i_cropleft * p_plane->i_visible_pitch) / p_pic->p->i_visible_pitch; i_ycrop = ( p_sys->i_croptop * p_plane->i_visible_lines) / p_pic->p->i_visible_lines; i_outwidth = ( p_filter->fmt_out.video.i_visible_width * p_outplane->i_visible_pitch ) / p_outpic->p->i_visible_pitch; i_outheight = ( p_filter->fmt_out.video.i_visible_height * p_outplane->i_visible_lines ) / p_outpic->p->i_visible_lines; i_xpadd = ( p_sys->i_paddleft * p_outplane->i_visible_pitch ) / p_outpic->p->i_visible_pitch; i_ypadd = ( p_sys->i_paddtop * p_outplane->i_visible_lines ) / p_outpic->p->i_visible_lines; /* Crop the top */ p_in += i_ycrop * p_plane->i_pitch; /* Padd on the top */ vlc_memset( p_out, i_padd_color, i_ypadd * p_outplane->i_pitch ); p_out += i_ypadd * p_outplane->i_pitch; int i_line; for( i_line = 0; i_line < i_height; i_line++ ) { uint8_t *p_in_next = p_in + p_plane->i_pitch; uint8_t *p_out_next = p_out + p_outplane->i_pitch; /* Crop on the left */ p_in += i_xcrop * i_pixel_pitch; /* Padd on the left */ vlc_memset( p_out, i_padd_color, i_xpadd * i_pixel_pitch ); p_out += i_xpadd * i_pixel_pitch; /* Copy the image and crop on the right */ vlc_memcpy( p_out, p_in, i_width * i_pixel_pitch ); p_out += i_width * i_pixel_pitch; p_in += i_width * i_pixel_pitch; /* Padd on the right */ vlc_memset( p_out, i_padd_color, ( i_outwidth - i_xpadd - i_width ) * i_pixel_pitch ); /* Got to begining of the next line */ p_in = p_in_next; p_out = p_out_next; } /* Padd on the bottom */ vlc_memset( p_out, i_padd_color, ( i_outheight - i_ypadd - i_height ) * p_outplane->i_pitch ); } return CopyInfoAndRelease( p_outpic, p_pic ); }
/** * It filters a video plane */ static void FilterPlanar( uint8_t *p_out, int i_out_pitch, const uint8_t *p_in, int i_in_pitch, int i_copy_pitch, int i_copy_lines, int i_pixel_black, const panoramix_filter_t *p_cfg, uint8_t p_lut[ACCURACY + 1][256], int lambdav[2][ACCURACY/2], int lambdah[2][ACCURACY/2] ) { /* */ assert( !p_cfg->black.i_left || !p_cfg->attenuate.i_left ); assert( !p_cfg->black.i_right || !p_cfg->attenuate.i_right ); assert( !p_cfg->black.i_top || !p_cfg->attenuate.i_top ); assert( !p_cfg->black.i_bottom || !p_cfg->attenuate.i_bottom ); const int i_out_width = p_cfg->black.i_left + i_copy_pitch + p_cfg->black.i_right; /* Top black border */ for( int b = 0; b < p_cfg->black.i_top; b++ ) { vlc_memset( p_out, i_pixel_black, i_out_width ); p_out += i_out_pitch; } for( int y = 0; y < i_copy_lines; y++ ) { const uint8_t *p_src = p_in; uint8_t *p_dst = p_out; /* Black border on the left */ if( p_cfg->black.i_left > 0 ) { memset( p_dst, i_pixel_black, p_cfg->black.i_left ); p_dst += p_cfg->black.i_left; } /* Attenuated video on the left */ for( int i = 0; i < p_cfg->attenuate.i_left; i++ ) *p_dst++ = p_lut[lambdav[0][i]][*p_src++]; /* Unmodified video */ const int i_unmodified_width = i_copy_pitch - p_cfg->attenuate.i_left - p_cfg->attenuate.i_right; vlc_memcpy( p_dst, p_src, i_unmodified_width ); p_dst += i_unmodified_width; p_src += i_unmodified_width; /* Attenuated video on the right */ for( int i = 0; i < p_cfg->attenuate.i_right; i++ ) *p_dst++ = p_lut[lambdav[1][i]][*p_src++]; /* Black border on the right */ if( p_cfg->black.i_right > 0 ) { memset( p_dst, i_pixel_black, p_cfg->black.i_right ); p_dst += p_cfg->black.i_right; } /* Attenuate complete line at top/bottom */ const bool b_attenuate_top = y < p_cfg->attenuate.i_top; const bool b_attenuate_bottom = y >= i_copy_lines - p_cfg->attenuate.i_bottom; if( b_attenuate_top || b_attenuate_bottom ) { const int i_index = b_attenuate_top ? lambdah[0][y] : lambdah[1][y - (i_copy_lines - p_cfg->attenuate.i_bottom)]; uint8_t *p_dst = &p_out[0]; for( int i = 0; i < i_out_width; i++) p_dst[i] = p_lut[i_index][p_dst[i]]; } /* */ p_in += i_in_pitch; p_out += i_out_pitch; } /* Bottom black border */ for( int b = 0; b < p_cfg->black.i_bottom; b++ ) { vlc_memset( p_out, i_pixel_black, i_out_width ); p_out += i_out_pitch; } }