1
mirror of https://code.videolan.org/videolan/vlc synced 2024-09-28 23:09:59 +02:00
vlc/modules/visualization/goom.c
Steve Lhomme 9aed0277b2 goom: use VLC_CODEC_XRGB instead of VLC_CODEC_RGB32
This is the format that will be used once the mask is "fixed".

No need to provide a format with a mask here.
2023-09-24 19:57:38 +00:00

392 lines
12 KiB
C

/*****************************************************************************
* goom.c: based on libgoom (see http://ios.free.fr/?page=projet&quoi=1)
*****************************************************************************
* Copyright (C) 2003-2011 VLC authors and VideoLAN
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@videolan.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_threads.h>
#include <vlc_plugin.h>
#include <vlc_aout.h> /* aout_FormatNbChannels, AOUT_FMTS_SIMILAR */
#include <vlc_vout.h> /* vout_*Picture, aout_filter_..tVout */
#include <vlc_filter.h>
#include <vlc_picture_pool.h>
#include <goom/goom.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( filter_t * );
#define WIDTH_TEXT N_("Goom display width")
#define HEIGHT_TEXT N_("Goom display height")
#define RES_LONGTEXT N_("This allows you to set the resolution of the " \
"Goom display (bigger resolution will be prettier but more CPU intensive).")
#define SPEED_TEXT N_("Goom animation speed")
#define SPEED_LONGTEXT N_("This allows you to set the animation speed " \
"(between 1 and 10, defaults to 6).")
#define MAX_SPEED 10
vlc_module_begin ()
set_shortname( N_("Goom"))
set_description( N_("Goom effect") )
set_subcategory( SUBCAT_AUDIO_VISUAL )
set_capability( "visualization", 0 )
add_integer( "goom-width", 800,
WIDTH_TEXT, RES_LONGTEXT )
add_integer( "goom-height", 500,
HEIGHT_TEXT, RES_LONGTEXT )
add_integer_with_range( "goom-speed", 6, 1, 10,
SPEED_TEXT, SPEED_LONGTEXT )
set_callback( Open )
add_shortcut( "goom" )
vlc_module_end ()
/*****************************************************************************
* Local prototypes
*****************************************************************************/
#define MAX_BLOCKS 100
#define GOOM_DELAY VLC_TICK_FROM_MS(400)
typedef struct
{
vlc_thread_t thread;
video_format_t fmt;
vout_thread_t *p_vout;
picture_pool_t *pool;
int i_speed;
vlc_mutex_t lock;
vlc_cond_t wait;
bool b_exit;
/* Audio properties */
unsigned i_channels;
/* Audio samples queue */
block_t *pp_blocks[MAX_BLOCKS];
int i_blocks;
date_t date;
} goom_thread_t;
static block_t *DoWork ( filter_t *, block_t * );
static void Flush( filter_t * );
static void *Thread( void * );
static const struct vlc_filter_operations filter_ops = {
.filter_audio = DoWork,
.flush = Flush,
.close = Close,
};
/*****************************************************************************
* Open: open a scope effect plugin
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t *)p_this;
goom_thread_t *p_thread;
/* Create goom thread */
p_filter->p_sys = p_thread = calloc( 1, sizeof(*p_thread) );
const int width = var_InheritInteger( p_filter, "goom-width" );
const int height = var_InheritInteger( p_filter, "goom-height" );
vlc_fourcc_t chroma = VLC_CODEC_XRGB;
video_format_Init(&p_thread->fmt, chroma);
p_thread->fmt.i_width = p_thread->fmt.i_visible_width = width;
p_thread->fmt.i_height = p_thread->fmt.i_visible_height = height;
p_thread->fmt.i_sar_num = p_thread->fmt.i_sar_den = 1;
p_thread->fmt.color_range = COLOR_RANGE_FULL;
/* TODO: the number of picture is arbitrary for now. */
p_thread->pool = picture_pool_NewFromFormat(&p_thread->fmt, 3);
if (p_thread->pool == NULL)
{
video_format_Clean(&p_thread->fmt);
free(p_thread);
return VLC_ENOMEM;
}
p_thread->p_vout = aout_filter_GetVout( p_filter, &p_thread->fmt );
if( p_thread->p_vout == NULL )
{
msg_Err( p_filter, "no suitable vout module" );
picture_pool_Release(p_thread->pool);
video_format_Clean(&p_thread->fmt);
free( p_thread );
return VLC_EGENERIC;
}
p_thread->i_speed = MAX_SPEED - var_InheritInteger( p_filter, "goom-speed" );
if( p_thread->i_speed < 0 )
p_thread->i_speed = 0;
vlc_mutex_init( &p_thread->lock );
vlc_cond_init( &p_thread->wait );
p_thread->i_blocks = 0;
date_Init( &p_thread->date, p_filter->fmt_in.audio.i_rate, 1 );
date_Set( &p_thread->date, VLC_TICK_0 );
p_thread->i_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
if( vlc_clone( &p_thread->thread, Thread, p_thread ) )
{
msg_Err( p_filter, "cannot launch goom thread" );
vout_Close( p_thread->p_vout );
picture_pool_Release(p_thread->pool);
video_format_Clean(&p_thread->fmt);
free( p_thread );
return VLC_EGENERIC;
}
p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
p_filter->fmt_out.audio = p_filter->fmt_in.audio;
p_filter->ops = &filter_ops;
return VLC_SUCCESS;
}
/*****************************************************************************
* DoWork: process samples buffer
*****************************************************************************
* This function queues the audio buffer to be processed by the goom thread
*****************************************************************************/
static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
{
goom_thread_t *p_thread = p_filter->p_sys;
block_t *p_block;
/* Queue sample */
vlc_mutex_lock( &p_thread->lock );
if( p_thread->i_blocks == MAX_BLOCKS )
{
vlc_mutex_unlock( &p_thread->lock );
return p_in_buf;
}
p_block = block_Alloc( p_in_buf->i_buffer );
if( !p_block )
{
vlc_mutex_unlock( &p_thread->lock );
return p_in_buf;
}
memcpy( p_block->p_buffer, p_in_buf->p_buffer, p_in_buf->i_buffer );
p_block->i_pts = p_in_buf->i_pts;
p_thread->pp_blocks[p_thread->i_blocks++] = p_block;
vlc_cond_signal( &p_thread->wait );
vlc_mutex_unlock( &p_thread->lock );
return p_in_buf;
}
static void Flush( filter_t *p_filter )
{
goom_thread_t *p_thread = p_filter->p_sys;
vout_FlushAll( p_thread->p_vout );
}
/*****************************************************************************
* float to s16 conversion
*****************************************************************************/
static inline int16_t FloatToInt16( float f )
{
if( f >= 1.0 )
return 32767;
else if( f < -1.0 )
return -32768;
else
return (int16_t)( f * 32768.0 );
}
/*****************************************************************************
* Fill buffer
*****************************************************************************/
static int FillBuffer( int16_t *p_data, int *pi_data,
date_t *pi_date, date_t *pi_date_end,
goom_thread_t *p_this )
{
int i_samples = 0;
block_t *p_block;
while( *pi_data < 512 )
{
if( !p_this->i_blocks ) return VLC_EGENERIC;
p_block = p_this->pp_blocks[0];
i_samples = __MIN( (unsigned)(512 - *pi_data),
p_block->i_buffer / sizeof(float) / p_this->i_channels );
/* Date management */
if( p_block->i_pts != VLC_TICK_INVALID &&
p_block->i_pts != date_Get( pi_date_end ) )
{
date_Set( pi_date_end, p_block->i_pts );
}
p_block->i_pts = VLC_TICK_INVALID;
date_Increment( pi_date_end, i_samples );
while( i_samples > 0 )
{
float *p_float = (float *)p_block->p_buffer;
p_data[*pi_data] = FloatToInt16( p_float[0] );
if( p_this->i_channels > 1 )
p_data[512 + *pi_data] = FloatToInt16( p_float[1] );
(*pi_data)++;
p_block->p_buffer += (sizeof(float) * p_this->i_channels);
p_block->i_buffer -= (sizeof(float) * p_this->i_channels);
i_samples--;
}
if( !p_block->i_buffer )
{
block_Release( p_block );
p_this->i_blocks--;
if( p_this->i_blocks )
memmove( p_this->pp_blocks, p_this->pp_blocks + 1,
p_this->i_blocks * sizeof(block_t *) );
}
}
*pi_date = *pi_date_end;
*pi_data = 0;
return VLC_SUCCESS;
}
/*****************************************************************************
* Thread:
*****************************************************************************/
static void *Thread( void *p_thread_data )
{
vlc_thread_set_name("vlc-goom");
goom_thread_t *p_thread = (goom_thread_t*)p_thread_data;
date_t i_pts;
int16_t p_data[2][512];
int i_data = 0, i_count = 0;
PluginInfo *p_plugin_info;
int canc = vlc_savecancel ();
p_plugin_info = goom_init( p_thread->fmt.i_width, p_thread->fmt.i_height );
plane_t src;
src.i_lines = p_thread->fmt.i_height;
src.i_pitch = p_thread->fmt.i_width * 4;
src.i_visible_lines = p_thread->fmt.i_height;
src.i_visible_pitch = p_thread->fmt.i_width * 4;
for( ;; )
{
uint32_t *plane;
picture_t *p_pic;
/* FIXME the way the update is done is not really good.
* Supurious wake up from p_thread->wait will make it generates a frame
* without using new samples (probably rare as we should not be waiting
* samples).
* The frame rate at which the video is generated is not well controlled
* nor the time at which each frame is displayed (not smooth)
*/
/* goom_update is damn slow, so just copy data and release the lock */
vlc_mutex_lock( &p_thread->lock );
if( !p_thread->b_exit &&
FillBuffer( (int16_t *)p_data, &i_data,
&i_pts, &p_thread->date, p_thread ) != VLC_SUCCESS )
vlc_cond_wait( &p_thread->wait, &p_thread->lock );
bool b_exit = p_thread->b_exit;
vlc_mutex_unlock( &p_thread->lock );
if( b_exit )
break;
/* Speed selection */
if( p_thread->i_speed && (++i_count % (p_thread->i_speed+1)) ) continue;
/* Frame dropping if necessary */
if( date_Get( &i_pts ) + GOOM_DELAY <= vlc_tick_now() ) continue;
plane = goom_update( p_plugin_info, p_data, 0, 0.0,
NULL, NULL );
p_pic = picture_pool_Wait( p_thread->pool );
if( unlikely(p_pic == NULL) )
continue;
src.p_pixels = (uint8_t*)plane;
plane_CopyPixels(&p_pic->p[0], &src);
p_pic->date = date_Get( &i_pts ) + GOOM_DELAY;
p_pic->b_progressive = true;
vout_PutPicture( p_thread->p_vout, p_pic );
}
goom_close( p_plugin_info );
vlc_restorecancel (canc);
return NULL;
}
/*****************************************************************************
* Close: close the plugin
*****************************************************************************/
static void Close( filter_t *p_filter )
{
goom_thread_t *p_thread = p_filter->p_sys;
/* Stop Goom Thread */
vlc_mutex_lock( &p_thread->lock );
p_thread->b_exit = true;
vlc_cond_signal( &p_thread->wait );
vlc_mutex_unlock( &p_thread->lock );
vlc_join( p_thread->thread, NULL );
/* Free data */
while( p_thread->i_blocks-- )
{
block_Release( p_thread->pp_blocks[p_thread->i_blocks] );
}
picture_pool_Release(p_thread->pool);
video_format_Clean(&p_thread->fmt);
free( p_thread );
}