From 997e94eafbb5aabb5416b89fd81eaf00761b9ce0 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sun, 12 Jul 2020 16:38:29 +0900 Subject: [PATCH] Fixed xine scope plugin functionality with xine 1.2.10. This resolves issue #19. Special thanks to xine developer Petri Hintukainen for his support to get passed the last hurdle. Signed-off-by: Michele Calgaro (cherry picked from commit c5f901c03ec2cb61d2c2820d81d2ecf26e43d70a) --- amarok/src/engine/xine/xine-engine.cpp | 25 +++--- amarok/src/engine/xine/xine-scope.c | 104 +++++++++++++++++-------- amarok/src/engine/xine/xine-scope.h | 22 +++--- 3 files changed, 94 insertions(+), 57 deletions(-) diff --git a/amarok/src/engine/xine/xine-engine.cpp b/amarok/src/engine/xine/xine-engine.cpp index 2f6344e5..7b9230ed 100644 --- a/amarok/src/engine/xine/xine-engine.cpp +++ b/amarok/src/engine/xine/xine-engine.cpp @@ -147,6 +147,11 @@ XineEngine::init() xine_init( m_xine ); +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + xine_register_plugins( m_xine, scope_plugin_info ); +#endif + makeNewStream(); #ifndef XINE_SAFE_MODE @@ -190,9 +195,10 @@ XineEngine::makeNewStream() (void*)this ); #ifndef XINE_SAFE_MODE -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \ - (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10) - //implemented in xine-scope.h +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + m_post = xine_post_init( m_xine, "amarok-scope", 1, &m_audioPort, NULL ); +#else m_post = scope_plugin_new( m_xine, m_audioPort ); #endif @@ -267,12 +273,9 @@ XineEngine::load( const KURL &url, bool isStream ) //we must ensure the scope is pruned of old buffers timerEvent( 0 ); -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \ - (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10) xine_post_out_t *source = xine_get_audio_source( m_stream ); xine_post_in_t *target = (xine_post_in_t*)xine_post_input( m_post, const_cast("audio in") ); xine_post_wire( source, target ); -#endif #endif playlistChanged(); @@ -724,10 +727,8 @@ XineEngine::scope() if( !m_post || !m_stream || xine_get_status( m_stream ) != XINE_STATUS_PLAY ) return m_scope; -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \ - (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10) MyNode* const myList = scope_plugin_list( m_post ); - metronom_t* const myMetronom = scope_plugin_metronom( m_post ); + const int64_t pts_per_smpls = scope_plugin_pts_per_smpls( m_post ); const int myChannels = scope_plugin_channels( m_post ); int scopeidx = 0; @@ -752,7 +753,7 @@ XineEngine::scope() diff = m_currentVpts; diff -= best_node->vpts; diff *= 1<<16; - diff /= myMetronom->pts_per_smpls; + diff /= pts_per_smpls; const int16_t* data16 = best_node->mem; @@ -784,7 +785,6 @@ XineEngine::scope() } Log::scopeCallCount++; -#endif return m_scope; } @@ -795,8 +795,6 @@ XineEngine::timerEvent( TQTimerEvent* ) if ( !m_stream ) return; -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \ - (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10) //here we prune the buffer list regularly MyNode *myList = scope_plugin_list( m_post ); @@ -826,7 +824,6 @@ XineEngine::timerEvent( TQTimerEvent* ) prev = node; } -#endif } Amarok::PluginConfig* diff --git a/amarok/src/engine/xine/xine-scope.c b/amarok/src/engine/xine/xine-scope.c index c2ecf5ca..0fd39bc3 100644 --- a/amarok/src/engine/xine/xine-scope.c +++ b/amarok/src/engine/xine/xine-scope.c @@ -18,8 +18,7 @@ typedef struct scope_plugin_s scope_plugin_t; struct scope_plugin_s { post_plugin_t post; - - metronom_t metronom; + int64_t pts_per_smpls; int channels; MyNode *list; }; @@ -31,8 +30,8 @@ struct scope_plugin_s static int scope_port_open( xine_audio_port_t *port_gen, xine_stream_t *stream, uint32_t bits, uint32_t rate, int mode ) { - #define port ((post_audio_port_t*)port_gen) - #define this ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post) + post_audio_port_t *port = (post_audio_port_t *)port_gen; + scope_plugin_t *this = (scope_plugin_t*)port->post; _x_post_rewire( (post_plugin_t*)port->post ); _x_post_inc_usage( port ); @@ -44,17 +43,28 @@ scope_port_open( xine_audio_port_t *port_gen, xine_stream_t *stream, uint32_t bi this->channels = _x_ao_mode2channels( mode ); - return port->original_port->open( port->original_port, stream, bits, rate, mode ); + int ret = port->original_port->open( port->original_port, stream, bits, rate, mode ); +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + this->pts_per_smpls = ((uint32_t)90000 * (uint32_t)32768) / rate; +#else + this->pts_per_smpls = stream->metronom->pts_per_smpls; +#endif + return ret; } static void scope_port_close( xine_audio_port_t *port_gen, xine_stream_t *stream ) { - MyNode *node; + post_audio_port_t *port = (post_audio_port_t *)port_gen; + scope_plugin_t *this = (scope_plugin_t*)port->post; /* ensure the buffers are deleted during the next XineEngine::timerEvent() */ + MyNode *node; for( node = this->list->next; node != this->list; node = node->next ) + { node->vpts = node->vpts_end = -1; + } port->stream = NULL; port->original_port->close( port->original_port, stream ); @@ -65,27 +75,27 @@ scope_port_close( xine_audio_port_t *port_gen, xine_stream_t *stream ) static void scope_port_put_buffer( xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream ) { -#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \ - (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10) + post_audio_port_t *port = (post_audio_port_t *)port_gen; + scope_plugin_t *this = (scope_plugin_t*)port->post; /* FIXME With 8-bit samples the scope won't work correctly. For a special 8-bit code path, the sample size could be checked like this: if( port->bits == 8 ) */ const int num_samples = buf->num_frames * this->channels; - metronom_t *myMetronom = &this->metronom; MyNode *new_node; - /* I keep my own metronom because xine wouldn't for some reason */ - memcpy( &this->metronom, stream->metronom, sizeof(metronom_t) ); - new_node = malloc( sizeof(MyNode) ); - new_node->vpts = myMetronom->got_audio_samples( myMetronom, buf->vpts, buf->num_frames ); +#ifdef METRONOM_VPTS + new_node->vpts = stream->metronom->get_option(stream->metronom, METRONOM_VPTS); +#else + new_node->vpts = stream->metronom->got_audio_samples( stream->metronom, 0, 0 ); +#endif new_node->num_frames = buf->num_frames; new_node->mem = malloc( num_samples * 2 ); memcpy( new_node->mem, buf->mem, num_samples * 2 ); { int64_t - K = myMetronom->pts_per_smpls; /*smpls = 1<<16 samples*/ + K = this->pts_per_smpls; K *= num_samples; K /= (1<<16); K += new_node->vpts; @@ -99,10 +109,6 @@ scope_port_put_buffer( xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_st * this is thread-safe due to the way we handle the list in the GUI thread */ new_node->next = this->list->next; this->list->next = new_node; -#endif - - #undef port - #undef this } static void @@ -123,7 +129,6 @@ scope_dispose( post_plugin_t *this ) } while( node != list ); - free( this ); } @@ -132,10 +137,14 @@ scope_dispose( post_plugin_t *this ) * plugin init function * ************************/ -xine_post_t* -scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target ) +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) +static post_plugin_t* scope_plugin_new( post_class_t *class_gen, int inputs, xine_audio_port_t *audio_target[], xine_video_port_t *video_target[] ) +#else +xine_post_t* scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target ) +#endif { - scope_plugin_t *scope_plugin = xine_xmalloc( sizeof(scope_plugin_t) ); + scope_plugin_t *scope_plugin = calloc( 1, sizeof(scope_plugin_t) ); post_plugin_t *post_plugin = (post_plugin_t*)scope_plugin; { @@ -145,7 +154,12 @@ scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target ) _x_post_init( post_plugin, 1, 0 ); +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + port = _x_post_intercept_audio_port( post_plugin, audio_target[0], &input, &output ); +#else port = _x_post_intercept_audio_port( post_plugin, audio_target, &input, &output ); +#endif port->new_port.open = scope_port_open; port->new_port.close = scope_port_close; port->new_port.put_buffer = scope_port_put_buffer; @@ -161,32 +175,60 @@ scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target ) /* code is straight from xine_init_post() can't use that function as it only dlopens the plugins and our plugin is statically linked in */ - post_plugin->running_ticket = xine->port_ticket; post_plugin->xine = xine; #endif /* scope_plugin_t init */ - scope_plugin->list = xine_xmalloc( sizeof(MyNode) ); + scope_plugin->list = calloc( 1, sizeof(MyNode) ); scope_plugin->list->next = scope_plugin->list; +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + return post_plugin; +#else return &post_plugin->xine_post; +#endif } -MyNode* -scope_plugin_list( void *post ) +MyNode* scope_plugin_list( void *post ) { return ((scope_plugin_t*)post)->list; } -int -scope_plugin_channels( void *post ) +int scope_plugin_channels( void *post ) { return ((scope_plugin_t*)post)->channels; } -metronom_t* -scope_plugin_metronom( void *post ) +int64_t scope_plugin_pts_per_smpls( void *post ) +{ + return ((scope_plugin_t*)post)->pts_per_smpls; +} + +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) +static void *scope_init_plugin(xine_t *xine, const void *data) { - return &((scope_plugin_t*)post)->metronom; + static const post_class_t post_scope_class = { + .open_plugin = scope_plugin_new, + .identifier = "amarok-scope", + .description = "Amarok Scope", + .dispose = NULL, + }; + + (void)xine; + (void)data; + + return (void*)&post_scope_class; } + +static const post_info_t scope_special_info = { + .type = XINE_POST_TYPE_AUDIO_VISUALIZATION, +}; + +const plugin_info_t scope_plugin_info[] = { + { PLUGIN_POST, 10, "amarok-scope", XINE_VERSION_CODE, &scope_special_info, scope_init_plugin }, + { PLUGIN_NONE, 0, NULL, 0, NULL, NULL } +}; +#endif diff --git a/amarok/src/engine/xine/xine-scope.h b/amarok/src/engine/xine/xine-scope.h index ce2d7ee7..263e27fb 100644 --- a/amarok/src/engine/xine/xine-scope.h +++ b/amarok/src/engine/xine/xine-scope.h @@ -12,6 +12,7 @@ #include #include +#include typedef struct my_node_s MyNode; @@ -28,21 +29,18 @@ struct my_node_s extern "C" { #endif - xine_post_t* - scope_plugin_new( xine_t*, xine_audio_port_t* ); - - /* we sacrifice type-safety here because some GCCs appear broken - * and choke on redefining the xine_post_t typedef - */ +#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \ + (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10) + extern const plugin_info_t scope_plugin_info[]; +#else + xine_post_t* scope_plugin_new( xine_t*, xine_audio_port_t* ); +#endif + int64_t scope_plugin_pts_per_smpls( void* ); - MyNode* - scope_plugin_list( void* ); + MyNode* scope_plugin_list( void* ); - int - scope_plugin_channels( void* ); + int scope_plugin_channels( void* ); - metronom_t* - scope_plugin_metronom( void* ); #ifdef __cplusplus } #endif