[vlmc-devel] [PATCH] Integrate libVLC consumer into VLMC

yikei lu luyikei.qmltu at gmail.com
Fri Jul 22 17:09:34 CEST 2016


2016-07-23 0:03 GMT+09:00 Paweł Goliński <golpaw1 at gmail.com>:
>
>> Wiadomość napisana przez yikei lu <luyikei.qmltu at gmail.com> w dniu 22.07.2016, o godz. 16:59:
>>
>> 2016-07-22 3:07 GMT+09:00 Pawel Golinski <golpaw1 at gmail.com>:
>>
>> I didn't look at the actual vlc consuemr code, so I do it here. Sorry
>>
>>> ---
>>> src/Backend/MLT/MLTBackend.cpp                     |  15 +
>>> src/Backend/MLT/modules/libvlc/consumer_libvlc.c   | 559 +++++++++++++++++++++
>>> src/Backend/MLT/modules/libvlc/consumer_libvlc.yml |  70 +++
>>> .../MLT/modules/libvlc/consumer_libvlc_window.yml  |  39 ++
>>> src/CMakeLists.txt                                 |   8 +-
>>> 5 files changed, 689 insertions(+), 2 deletions(-)
>>> create mode 100644 src/Backend/MLT/modules/libvlc/consumer_libvlc.c
>>> create mode 100644 src/Backend/MLT/modules/libvlc/consumer_libvlc.yml
>>> create mode 100644 src/Backend/MLT/modules/libvlc/consumer_libvlc_window.yml
>>>
>>> diff --git a/src/Backend/MLT/MLTBackend.cpp b/src/Backend/MLT/MLTBackend.cpp
>>> index 3d39930..c466995 100644
>>> --- a/src/Backend/MLT/MLTBackend.cpp
>>> +++ b/src/Backend/MLT/MLTBackend.cpp
>>> @@ -5,6 +5,7 @@
>>>  * Copyright (C) 2008-2016 VideoLAN
>>>  *
>>>  * Authors: Yikei Lu <luyikei.qmltu at gmail.com>
>>> + *          Pawel Golinski <golpaw1 at gmail.com>
>>>  *
>>>  * This program is free software; you can redistribute it and/or
>>>  * modify it under the terms of the GNU General Public License
>>> @@ -43,6 +44,15 @@ using namespace Backend::MLT;
>>> static Backend::IBackend::LogHandler    staticLogHandler;
>>> static std::mutex                       logMutex;
>>>
>>> +extern "C" mlt_consumer consumer_libvlc_init( mlt_profile profile, mlt_service_type type, const char *id, const void *arg );
>>> +
>>> +static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
>>> +{
>>> +    char file[ 4096 ];
>>> +    snprintf( file, 4096, "%s%s", MLT_MODULES_PATH, (char*)data );
>>> +    return mlt_properties_parse_yaml( file );
>>> +}
>>> +
>>> IBackend*
>>> Backend::instance()
>>> {
>>> @@ -54,6 +64,11 @@ MLTBackend::MLTBackend()
>>>     m_mltRepo = Mlt::Factory::init();
>>>     m_profile.setFrameRate( 2997, 100 );
>>>
>>> +    m_mltRepo->register_service( consumer_type, "libvlc", (mlt_register_callback)consumer_libvlc_init );
>>> +    m_mltRepo->register_service( consumer_type, "libvlc_window", (mlt_register_callback)consumer_libvlc_init );
>>> +    m_mltRepo->register_metadata( consumer_type, "libvlc", metadata, (void*)"/libvlc/consumer_libvlc.yml" );
>>> +    m_mltRepo->register_metadata( consumer_type, "libvlc_window", metadata, (void*)"/libvlc/consumer_libvlc_window.yml" );
>>> +
>>>     for ( int i = 0; i < m_mltRepo->filters()->count(); ++i )
>>>     {
>>>         auto pro = std::unique_ptr<Mlt::Properties>( m_mltRepo->metadata( filter_type, m_mltRepo->filters()->get_name( i ) ) );
>>> diff --git a/src/Backend/MLT/modules/libvlc/consumer_libvlc.c b/src/Backend/MLT/modules/libvlc/consumer_libvlc.c
>>> new file mode 100644
>>> index 0000000..a34f8fa
>>> --- /dev/null
>>> +++ b/src/Backend/MLT/modules/libvlc/consumer_libvlc.c
>>> @@ -0,0 +1,559 @@
>>> +/*****************************************************************************
>>> + * consumer_libvlc.c: libVLC consumer plugin for MLT
>>> + *****************************************************************************
>>> + * Copyright (C) 2008-2016 VideoLAN
>>> + *
>>> + * Authors: Pawel Golinski <golpaw1 at gmail.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License
>>> + * as published by the Free Software Foundation; either version 2
>>> + * 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 General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU 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.
>>> + *****************************************************************************/
>>> +
>>> +#include <framework/mlt.h>
>>> +
>>> +#include <vlc/vlc.h>
>>> +
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <assert.h>
>>> +#include <string.h>
>>> +
>>> +#define VIDEO_COOKIE 0
>>> +#define AUDIO_COOKIE 1
>>> +
>>> +#define INITIAL_POSITION -1
>>> +
>>> +// Debug code
>>> +
>>> +pthread_mutex_t log_mutex;
>>> +
>>> +static void log_cb( void *data, int level, const libvlc_log_t *ctx, const char *fmt, va_list args )
>>> +{
>>> +       pthread_mutex_lock( &log_mutex );
>>> +       printf( "VLC LOG: " );
>>> +       vprintf( fmt, args );
>>> +       printf( "\n" );
>>> +       pthread_mutex_unlock( &log_mutex );
>>> +}
>>> +
>>> +typedef struct consumer_libvlc_s *consumer_libvlc;
>>> +
>>> +struct consumer_libvlc_s
>>> +{
>>> +       mlt_consumer parent;
>>> +       libvlc_instance_t *vlc;
>>> +       libvlc_media_t *media;
>>> +       libvlc_media_player_t *media_player;
>>> +       libvlc_event_manager_t *mp_manager;
>>> +       int64_t latest_video_pts;
>>> +       int64_t latest_audio_pts;
>>> +       mlt_deque frame_queue;
>>> +       pthread_mutex_t queue_mutex;
>>> +       mlt_position video_position;
>>> +       mlt_position audio_position;
>>> +       void *video_imem_data;
>>> +       void *audio_imem_data;
>>> +       int running;
>>> +       int output_to_window;
>>> +};
>>> +
>>> +static void setup_vlc( consumer_libvlc self );
>>> +static void setup_vlc_sout( consumer_libvlc self );
>>> +static int setup_vlc_window( consumer_libvlc self );
>>> +static int imem_get( void *data, const char* cookie, int64_t *dts, int64_t *pts,
>>> +                                        unsigned *flags, size_t *bufferSize, void **buffer );
>>> +static void imem_release( void *data, const char* cookie, size_t buffSize, void *buffer );
>>> +static int consumer_start( mlt_consumer parent );
>>> +static int consumer_stop( mlt_consumer parent );
>>> +static int consumer_is_stopped( mlt_consumer parent );
>>> +static void consumer_close( mlt_consumer parent );
>>> +static void consumer_purge( mlt_consumer parent );
>>> +static void mp_callback( const struct libvlc_event_t *evt, void *data );
>>> +
>>> +mlt_consumer consumer_libvlc_init( mlt_profile profile, mlt_service_type type, const char *id, const void *arg )
>>> +{
>>> +       int err;
>>> +       mlt_consumer parent = NULL;
>>> +       consumer_libvlc self = NULL;
>>> +
>>> +       // Allocate the consumer data structures
>>> +       parent = calloc( 1, sizeof( struct mlt_consumer_s ) );
>>
>> Why don't you use mlt_consumer_new?
>
> Dunno, got inspired by some MLT code elsewhere.
>
>>
>>> +       self = calloc( 1, sizeof( struct consumer_libvlc_s ) );
>>> +       assert( parent != NULL && self != NULL );
>>> +       err = mlt_consumer_init( parent, self, profile );
>>> +       assert( err == 0 );
>>> +
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent );
>>> +       mlt_properties_set_lcnumeric( properties, "C" );
>>> +       self->parent = parent;
>>> +
>>> +       // Set default libVLC specific properties
>>> +       mlt_properties_set( properties, "input_vcodec", "RGBA" );
>>> +       mlt_properties_set( properties, "input_acodec", "s16l" );
>>> +       mlt_properties_set( properties, "output_vcodec", "mp2v" );
>>> +       mlt_properties_set( properties, "output_acodec", "mpga" );
>>> +       mlt_properties_set_int( properties, "output_vb", 8000000 );
>>> +       mlt_properties_set_int( properties, "output_ab", 128000 );
>>> +       if ( self->output_to_window )
>>> +               mlt_properties_set_data( properties, "output_dst", arg, 0, NULL, NULL );
>>> +       else
>>> +               mlt_properties_set( properties, "output_dst", ( char* )arg );
>>> +       mlt_properties_set( properties, "output_mux", "ps" );
>>> +       mlt_properties_set( properties, "output_access", "file" );
>>> +
>>> +       self->vlc = libvlc_new( 0, NULL );
>>> +       assert( self->vlc != NULL );
>>> +
>>> +       // Debug code
>>> +       libvlc_log_set( self->vlc, log_cb, NULL );
>>> +       pthread_mutex_init( &log_mutex, NULL );
>>> +
>>> +       self->frame_queue = mlt_deque_init( );
>>> +       assert( self->frame_queue != NULL );
>>> +
>>> +       pthread_mutex_init( &self->queue_mutex, NULL );
>>> +
>>> +       parent->start = consumer_start;
>>> +       parent->stop = consumer_stop;
>>> +       parent->is_stopped = consumer_is_stopped;
>>> +       parent->close = consumer_close;
>>> +       parent->purge = consumer_purge;
>>> +
>>> +       // Set output_to_window flag if needed
>>> +       if ( !strcmp( id, "libvlc_window" ) )
>>> +               self->output_to_window = 1;
>>> +
>>> +       return parent;
>>> +}
>>> +
>>> +static void setup_vlc( consumer_libvlc self )
>>> +{
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +
>>> +       // imem setup phase
>>> +
>>> +       // Allocate buffers
>>> +       char imem_video_conf[ 512 ];
>>> +       char imem_audio_conf[ 512 ];
>>> +       char imem_get_conf[ 512 ];
>>> +       char imem_release_conf[ 512 ];
>>> +       char imem_data_conf[ 512 ];
>>> +
>>> +       // We will create media using imem MRL
>>> +       sprintf( imem_video_conf, "imem://width=%i:height=%i:dar=%s:fps=%s/1:cookie=0:codec=%s:cat=2:caching=0",
>>> +               mlt_properties_get_int( properties, "width" ),
>>> +               mlt_properties_get_int( properties, "height" ),
>>> +               mlt_properties_get( properties, "display_ratio" ),
>>> +               mlt_properties_get( properties, "fps" ),
>>> +               mlt_properties_get( properties, "input_vcodec" ) );
>>> +
>>> +       // Audio stream will be added as input slave
>>> +       sprintf( imem_audio_conf, ":input-slave=imem://cookie=1:cat=1:codec=%s:samplerate=%d:channels=%d:caching=0",
>>> +               mlt_properties_get( properties, "input_acodec" ),
>>> +               mlt_properties_get_int( properties, "frequency" ),
>>> +               mlt_properties_get_int( properties, "channels" ) );
>>> +
>>> +       // This configures imem callbacks
>>> +       sprintf( imem_get_conf,
>>> +               ":imem-get=%" PRIdPTR,
>>> +               (intptr_t)(void*)&imem_get );
>>> +
>>> +       sprintf( imem_release_conf,
>>> +               ":imem-release=%" PRIdPTR,
>>> +               (intptr_t)(void*)&imem_release );
>>> +
>>> +       sprintf( imem_data_conf,
>>> +               ":imem-data=%" PRIdPTR,
>>> +               (intptr_t)(void*)self );
>>> +
>>> +       // Create media...
>>> +       self->media = libvlc_media_new_location( self->vlc, imem_video_conf );
>>> +       assert( self->media != NULL );
>>> +
>>> +       // ...and apply configuration parameters.
>>> +       libvlc_media_add_option( self->media, imem_audio_conf );
>>> +       libvlc_media_add_option( self->media, imem_get_conf );
>>> +       libvlc_media_add_option( self->media, imem_release_conf );
>>> +       libvlc_media_add_option( self->media, imem_data_conf );
>>> +
>>> +       // Setup sout chain if we're not outputting to window
>>> +       if ( !self->output_to_window )
>>> +       {
>>> +               setup_vlc_sout( self );
>>> +       }
>>> +}
>>> +
>>> +static void setup_vlc_sout( consumer_libvlc self )
>>> +{
>>> +       assert( self->media != NULL );
>>> +
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +
>>> +       char sout_conf[ 512 ];
>>> +
>>> +       // This configures file output
>>> +       sprintf( sout_conf, ":sout=#transcode{"
>>> +               "vcodec=%s,fps=%s,width=%d,height=%d,vb=%d,"
>>> +               "acodec=%s,channels=%d,samplerate=%d,ab=%d}"
>>> +               ":standard{access=%s,mux=%s,dst=\"%s\"}",
>>> +               mlt_properties_get( properties, "output_vcodec" ),
>>> +               mlt_properties_get( properties, "fps" ),
>>> +               mlt_properties_get_int( properties, "width" ),
>>> +               mlt_properties_get_int( properties, "height" ),
>>> +               mlt_properties_get_int( properties, "output_vb" ),
>>> +               mlt_properties_get( properties, "output_acodec" ),
>>> +               mlt_properties_get_int( properties, "channels" ),
>>> +               mlt_properties_get_int( properties, "frequency" ),
>>> +               mlt_properties_get_int( properties, "output_ab" ),
>>> +               mlt_properties_get( properties, "output_access" ),
>>> +               mlt_properties_get( properties, "output_mux" ),
>>> +               mlt_properties_get( properties, "output_dst" ) );
>>> +
>>> +       libvlc_media_add_option( self->media, sout_conf );
>>> +}
>>> +
>>> +static int setup_vlc_window( consumer_libvlc self )
>>> +{
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +
>>> +       char *window_type = mlt_properties_get( properties, "window_type" );
>>> +       void *window_handle = mlt_properties_get_data( properties, "output_dst", NULL );
>>> +
>>> +       if ( window_type != NULL && window_handle != NULL )
>>> +       {
>>> +               if ( !strcmp( window_type, "nsobject") )
>>> +               {
>>> +                       libvlc_media_player_set_nsobject( self->media_player, window_handle );
>>> +               }
>>> +               else if ( !strcmp( window_type, "xwindow" ) )
>>> +               {
>>> +                       libvlc_media_player_set_xwindow( self->media_player, ( uint32_t )window_handle );
>>> +               }
>>> +               else if ( !strcmp( window_type, "hwnd" ) )
>>> +               {
>>> +                       libvlc_media_player_set_hwnd( self->media_player, window_handle );
>>> +               }
>>> +               else
>>> +               {
>>> +                       // Some unknown window_type was passed
>>> +                       return 1;
>>> +               }
>>> +
>>> +               // Setup finished successfully
>>> +               return 0;
>>> +       }
>>> +       else
>>> +       {
>>> +               // We failed to get window_type and/or window_handle
>>> +               return 1;
>>> +       }
>>> +}
>>> +
>>> +static int imem_get( void *data, const char* cookie, int64_t *dts, int64_t *pts,
>>> +                                        uint32_t *flags, size_t *bufferSize, void **buffer )
>>> +{
>>> +       consumer_libvlc self = data;
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +       mlt_frame frame = NULL;
>>> +       // Whether or not fetched frame need releasing
>>> +       int cleanup_frame = 0;
>>> +       *buffer = NULL;
>>> +
>>> +       int cookie_int = cookie[ 0 ] - '0';
>>> +
>>> +       // Get data if needed
>>> +       pthread_mutex_lock( &self->queue_mutex );
>>> +
>>> +       frame = mlt_deque_pop_front( self->frame_queue );
>>> +
>>> +       // If we got frame from queue, we need to release it later
>>> +       if ( frame != NULL )
>>> +               cleanup_frame = 1;
>>> +       else
>>> +               frame = mlt_consumer_get_frame( self->parent );
>>
>> I think you should also free frame even if you get it from
>> mlt_consumer_get_frame.
>>
>> In mlt_service.c
>> -----------------------------------------
>> static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index )
>> ....
>> *frame = mlt_frame_init( self );
>> -----------------------------------------
>>
>>
>>> +
>>> +       if ( cookie_int == AUDIO_COOKIE && self->running )
>>> +       {
>>> +               assert( frame != NULL );
>>> +               mlt_position current_position = mlt_frame_original_position( frame );
>>> +
>>> +               // We terminate imem if we got repeated frame, as this means pause
>>> +               if ( current_position == self->audio_position )
>>> +               {
>>> +                       self->running = 0;
>>> +                       pthread_mutex_unlock( &self->queue_mutex );
>>> +                       return 1;
>>> +               }
>>> +               else
>>> +               {
>>> +                       // Update position
>>> +                       self->audio_position = current_position;
>>> +
>>> +                       // This is used to pass frames to imem_release() if they need cleanup
>>> +                       self->audio_imem_data = NULL;
>>> +
>>> +                       mlt_audio_format afmt = mlt_audio_s16;
>>> +                       double fps = mlt_properties_get_double( properties, "fps" );
>>> +                       int frequency = mlt_properties_get_int( properties, "frequency" );
>>> +                       int channels = mlt_properties_get_int( properties, "channels" );
>>> +                       int samples = mlt_sample_calculator( fps, frequency, self->audio_position );
>>> +                       double pts_diff = ( double )samples / ( double )frequency * 1000000.0;
>>> +
>>> +                       mlt_frame_get_audio( frame, buffer, &afmt, &frequency, &channels, &samples );
>>> +                       *bufferSize = samples * sizeof( int16_t ) * channels;
>>> +
>>> +                       *pts = self->latest_audio_pts + pts_diff + 0.5;
>>> +                       *dts = *pts;
>>> +
>>> +                       self->latest_audio_pts = *pts;
>>> +
>>> +                       if ( cleanup_frame )
>>> +                               self->audio_imem_data = frame;
>>> +                       else
>>> +                               mlt_deque_push_back( self->frame_queue, frame );
>>> +               }
>>> +       }
>>> +       else if ( cookie_int == VIDEO_COOKIE && self->running )
>>> +       {
>>> +               assert( frame != NULL );
>>> +               mlt_position current_position = mlt_frame_original_position( frame );
>>> +
>>> +               if ( current_position == self->video_position )
>>> +               {
>>> +                       self->running = 0;
>>> +                       pthread_mutex_unlock( &self->queue_mutex );
>>> +                       return 1;
>>> +               }
>>> +               else
>>> +               {
>>> +                       self->video_position = current_position;
>>> +
>>> +                       self->video_imem_data = NULL;
>>> +
>>> +                       double fps = mlt_properties_get_double( properties, "fps" );
>>> +                       double pts_diff = 1.0 / fps * 1000000.0;
>>> +
>>> +                       mlt_image_format vfmt = mlt_image_rgb24a;
>>> +                       int width = mlt_properties_get_int( properties, "width" );
>>> +                       int height = mlt_properties_get_int( properties, "height" );
>>> +                       mlt_frame_get_image( frame, ( uint8_t ** )buffer, &vfmt, &width, &height, 0 );
>>> +                       *bufferSize = mlt_image_format_size( vfmt, width, height, NULL );
>>> +
>>> +                       *pts = self->latest_video_pts + pts_diff;
>>> +                       *dts = *pts;
>>> +
>>> +                       self->latest_video_pts = *pts;
>>> +
>>> +                       if ( cleanup_frame )
>>> +                               self->video_imem_data = frame;
>>> +                       else
>>> +                               mlt_deque_push_back( self->frame_queue, frame );
>>
>> I think mlt_deque should be max size.



>
> No difference - VLC kinda paces sound and video together, so the queue size is 1 max in practice.
>

It's fail-safe.

>>
>>> +                       }
>>> +       }
>>> +       else if ( self->running )
>>> +       {
>>> +               // Invalid cookie
>>> +               assert( 0 );
>>> +       }
>>> +       pthread_mutex_unlock( &self->queue_mutex );
>>> +
>>> +       assert( frame != NULL );
>>> +       if ( *buffer == NULL )
>>> +               return 1;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static void imem_release( void *data, const char* cookie, size_t buffSize, void *buffer )
>>> +{
>>> +       consumer_libvlc self = data;
>>> +
>>> +       int cookie_int = cookie[ 0 ] - '0';
>>> +
>>> +       if ( cookie_int == VIDEO_COOKIE && self->running )
>>> +       {
>>> +               if ( self->video_imem_data )
>>> +               {
>>> +                       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +                       mlt_frame frame = self->video_imem_data;
>>> +                       mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
>>> +                       self->video_imem_data = NULL;
>>> +               }
>>> +       }
>>> +       else if ( cookie_int == AUDIO_COOKIE && self->running )
>>> +       {
>>> +               if ( self->audio_imem_data )
>>> +               {
>>> +                       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +                       mlt_frame frame = self->audio_imem_data;
>>> +                       mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
>>> +                       self->audio_imem_data = NULL;
>>> +
>>> +               }
>>> +       }
>>> +       else if ( self->running )
>>> +       {
>>> +               // Invalid cookie
>>> +               assert( 0 );
>>> +       }
>>
>> I think you need mlt_frame_close( frame );
>
> Looking into it now, obviously now there is some frame related memleak somewhere,
> but I think I saw somewhere that after emitting consumer-frame-show, MLT does
> frame cleanup automatically. I can be wrong though...
>

Basically, consumer_avformat.c does mlt_frame_close after the event.

>>
>>> +}
>>> +
>>> +static void mp_callback( const struct libvlc_event_t *evt, void *data )
>>> +{
>>> +       consumer_libvlc self = data;
>>> +       assert( self != NULL );
>>> +
>>> +       switch ( evt->type )
>>> +       {
>>> +               case libvlc_MediaPlayerStopped:
>>> +                       self->running = 0;
>>> +                       break;
>>> +
>>> +               default:
>>> +                       assert( 0 );
>>> +       }
>>> +}
>>> +
>>> +static int consumer_start( mlt_consumer parent )
>>> +{
>>> +       int err;
>>> +
>>> +       consumer_libvlc self = parent->child;
>>> +       assert( self != NULL );
>>> +
>>> +       mlt_properties properties = MLT_CONSUMER_PROPERTIES( self->parent );
>>> +
>>> +
>>> +       if ( consumer_is_stopped( parent ) )
>>> +       {
>>> +               // Free all previous resources
>>> +               if ( self->media_player )
>>> +               {
>>> +                       libvlc_media_player_release( self->media_player );
>>> +                       self->media_player = NULL;
>>> +               }
>>> +               if ( self->media )
>>> +               {
>>> +                       libvlc_media_release( self->media );
>>> +                       self->media = NULL;
>>> +               }
>>> +
>>> +               // Apply properties to new media
>>> +               setup_vlc( self );
>>> +               self->media_player = libvlc_media_player_new_from_media( self->media );
>>> +               assert( self->media_player != NULL );
>>> +
>>> +               // Set window output if we're using it
>>> +               if ( self->output_to_window )
>>> +               {
>>> +                       err = setup_vlc_window( self );
>>> +
>>> +                       if ( err )
>>> +                       {
>>> +                               char error_msg[] = "Wrong window_type and/or output_dst parameters supplied.\n";
>>> +                               char *window_type = mlt_properties_get( properties, "window_type" );
>>> +                               mlt_log_error( MLT_CONSUMER_SERVICE( self->parent ), error_msg );
>>> +                               mlt_events_fire( properties, "consumer-fatal-error", NULL );
>>> +                               return err;
>>> +                       }
>>> +               }
>>> +
>>> +               // Catch media_player stop
>>> +               self->mp_manager = libvlc_media_player_event_manager( self->media_player );
>>> +               assert( self->mp_manager != NULL );
>>> +               libvlc_event_attach( self->mp_manager, libvlc_MediaPlayerStopped, &mp_callback, self );
>>> +
>>> +               // Reset play heads
>>> +               self->video_position = INITIAL_POSITION;
>>> +               self->audio_position = INITIAL_POSITION;
>>> +
>>> +               // Run media player
>>> +               self->running = 1;
>>> +               err = libvlc_media_player_play( self->media_player );
>>> +
>>> +               // If we failed to play, we're not running
>>> +               if ( err ) {
>>> +                       self->running = 0;
>>> +               }
>>> +
>>> +               return err;
>>> +       }
>>> +       return 1;
>>> +}
>>> +
>>> +static int consumer_stop( mlt_consumer parent )
>>> +{
>>> +       consumer_libvlc self = parent->child;
>>> +       assert( self != NULL );
>>> +
>>> +       if ( self->media_player )
>>> +       {
>>> +               self->running = 0;
>>> +               libvlc_media_player_stop( self->media_player );
>>> +       }
>>> +
>>> +       // Reset pts counters
>>> +       self->latest_video_pts = 0;
>>> +       self->latest_audio_pts = 0;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int consumer_is_stopped( mlt_consumer parent )
>>> +{
>>> +       consumer_libvlc self = parent->child;
>>> +       assert( self != NULL );
>>> +
>>> +       if ( self->media_player )
>>> +       {
>>> +               return !self->running;
>>> +       }
>>> +
>>> +       return 1;
>>> +}
>>> +
>>> +static void consumer_purge( mlt_consumer parent )
>>> +{
>>> +       // We do nothing here, we purge on stop()
>>> +}
>>> +
>>> +static void consumer_close( mlt_consumer parent )
>>> +{
>>> +       if ( parent == NULL )
>>> +       {
>>> +               return;
>>> +       }
>>> +
>>> +       consumer_libvlc self = parent->child;
>>> +
>>> +       if ( self != NULL )
>>> +       {
>>> +               consumer_stop( parent );
>>> +
>>> +               if ( self->media_player )
>>> +                       libvlc_media_player_release( self->media_player );
>>> +
>>> +               if ( self->media )
>>> +                       libvlc_media_release( self->media );
>>> +
>>> +               if ( self->vlc )
>>> +                       libvlc_release( self->vlc );
>>> +
>>> +               pthread_mutex_destroy( &self->queue_mutex );
>>> +               free( self );
>>> +       }
>>> +
>>> +       parent->close = NULL;
>>> +       mlt_consumer_close( parent );
>>> +}
>>> diff --git a/src/Backend/MLT/modules/libvlc/consumer_libvlc.yml b/src/Backend/MLT/modules/libvlc/consumer_libvlc.yml
>>> new file mode 100644
>>> index 0000000..2776715
>>> --- /dev/null
>>> +++ b/src/Backend/MLT/modules/libvlc/consumer_libvlc.yml
>>> @@ -0,0 +1,70 @@
>>> +schema_version: 0.1
>>> +type: consumer
>>> +identifier: libvlc
>>> +title: libVLC
>>> +version: 1
>>> +creator: Pawel Golinski
>>> +license: GNU GPL
>>> +language: en
>>> +tags:
>>> +  - Audio
>>> +  - Video
>>> +description: >
>>> +  libVLC video and audio output module. It uses VLC "standard" module.
>>> +  It can be set up using usual MLT consumer properties and additional
>>> +  libVLC specific properties described here.
>>> +parameters:
>>> +  - identifier: output_dst
>>> +    argument: yes
>>> +    title: File/URL
>>> +    type: string
>>> +    description: "sout-standard-dst" option
>>> +    required: yes
>>> +
>>> +  - identifier: input_vcodec
>>> +    title: Input vcodec
>>> +    type: string
>>> +    description: Format, in which raw video frames will be supplied to the consumer.
>>> +    default: RGBA
>>> +
>>> +  - identifier: input_acodec
>>> +    title: Input acodec
>>> +    type: string
>>> +    description: Format, in which raw audio frames will be supplied to the consumer.
>>> +    default: s16l
>>> +
>>> +  - identifier: output_vcodec
>>> +    title: Output vcodec.
>>> +    type: string
>>> +    description: "sout-transcode-vcodec" option
>>> +    default: mp2v
>>> +
>>> +  - identifier: output_acodec
>>> +    title: Output acodec.
>>> +    type: string
>>> +    description: "sout-transcode-acodec" option
>>> +    default: mpga
>>> +
>>> +  - identifier: output_vb
>>> +    title: Output video bitrate.
>>> +    type: integer
>>> +    description: "sout-transcode-vb" option
>>> +    default: 8000000
>>> +
>>> +  - identifier: output_ab
>>> +    title: Output audio bitrate.
>>> +    type: integer
>>> +    description: "sout-transcode-ab" option
>>> +    default: 128000
>>> +
>>> +  - identifier: output_mux
>>> +    title: Output muxer.
>>> +    type: string
>>> +    description: "sout-standard-mux" option
>>> +    default: ps
>>> +
>>> +  - identifier: output_access
>>> +    title: Output method.
>>> +    type: string
>>> +    description: "sout-standard-access" option
>>> +    default: file
>>> diff --git a/src/Backend/MLT/modules/libvlc/consumer_libvlc_window.yml b/src/Backend/MLT/modules/libvlc/consumer_libvlc_window.yml
>>> new file mode 100644
>>> index 0000000..d2b7410
>>> --- /dev/null
>>> +++ b/src/Backend/MLT/modules/libvlc/consumer_libvlc_window.yml
>>> @@ -0,0 +1,39 @@
>>> +schema_version: 0.1
>>> +type: consumer
>>> +identifier: libvlc_window
>>> +title: libVLC Window
>>> +version: 1
>>> +creator: Pawel Golinski
>>> +license: GNU GPL
>>> +language: en
>>> +tags:
>>> +  - Audio
>>> +  - Video
>>> +description: >
>>> +  libVLC video and audio output module. It uses VLC window output.
>>> +  It can be set up using usual MLT consumer properties and additional
>>> +  libVLC specific properties described here.
>>> +parameters:
>>> +  - identifier: output_dst
>>> +    argument: yes
>>> +    title: Window handle
>>> +    description: Window, to which libVLC should render the media.
>>> +    required: yes
>>> +
>>> +  - identifier: window_type
>>> +    title: Window type
>>> +    type: string
>>> +    description: Type of the window, the output_dst points to (xwindow/nsobject/hwnd)
>>> +    required: yes
>>> +
>>> +  - identifier: input_vcodec
>>> +    title: Input vcodec
>>> +    type: string
>>> +    description: Format, in which raw video frames will be supplied to the consumer.
>>> +    default: RGBA
>>> +
>>> +  - identifier: input_acodec
>>> +    title: Input acodec
>>> +    type: string
>>> +    description: Format, in which raw audio frames will be supplied to the consumer.
>>> +    default: s16l
>>> \ No newline at end of file
>>> diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
>>> index a85cf0a..be37f15 100644
>>> --- a/src/CMakeLists.txt
>>> +++ b/src/CMakeLists.txt
>>> @@ -55,6 +55,9 @@ INCLUDE_DIRECTORIES(${FREI0R_INCLUDE_DIR})
>>> # Instruct CMake to run moc automatically when needed.
>>> SET(CMAKE_AUTOMOC ON)
>>>
>>> +SET(MLT_MODULES Backend/MLT/modules)
>>> +ADD_DEFINITIONS(-DMLT_MODULES_PATH="${CMAKE_CURRENT_BINARY_DIR}/src/${MLT_MODULES}")
>>> +
>>> SET(VLMC_SRCS
>>>     Commands/Commands.cpp
>>>     Backend/IBackend.h
>>> @@ -74,6 +77,7 @@ SET(VLMC_SRCS
>>>     Backend/MLT/MLTFilter.cpp
>>>     Backend/MLT/MLTTransition.cpp
>>>     Backend/MLT/MLTMultiTrack.cpp
>>> +    Backend/MLT/modules/libvlc/consumer_libvlc.c
>>>     EffectsEngine/EffectHelper.cpp
>>>     Library/Library.cpp
>>>     Library/MediaContainer.cpp
>>> @@ -314,14 +318,14 @@ ENDIF(UNIX)
>>>
>>> if( APPLE )
>>>     set(APPLICATION_BUNDLE ${CMAKE_BINARY_DIR}/bin/vlmc.app)
>>> -    set(APPLICATION_LIB_DIR ${LIBVLC_LIB_DIR})
>>> +    set(APPLICATION_LIB_DIR ${LIBVLC_LIBRARY_DIRS})
>>>
>>>     # re-enable this when we start addressing redistribution
>>>     # message(STATUS "Looking for bundle ${APPLICATION_BUNDLE} with library path ${APPLICATION_LIB_DIR}")
>>>     # install(CODE "include(BundleUtilities)
>>>     add_custom_command(TARGET vlmc
>>>         POST_BUILD
>>> -        COMMAND ${CMAKE_SOURCE_DIR}/cmake/FixBundle.sh ${APPLICATION_BUNDLE}/Contents/MacOS ${LIBVLC_LIB_DIR}
>>> +        COMMAND ${CMAKE_SOURCE_DIR}/cmake/FixBundle.sh ${APPLICATION_BUNDLE}/Contents/MacOS ${LIBVLC_LIBRARY_DIRS}
>>>         COMMENT "Fixing application bundle for local run")
>>>     # fixup_bundle(\"${APPLICATION_BUNDLE}\" \"\" \"${APPLICATION_LIB_DIR}\")" COMPONENT Runtime)
>>> endif()
>>> --
>>> 2.7.4 (Apple Git-66)
>>>
>>> _______________________________________________
>>> Vlmc-devel mailing list
>>> Vlmc-devel at videolan.org
>>> https://mailman.videolan.org/listinfo/vlmc-devel
>> _______________________________________________
>> Vlmc-devel mailing list
>> Vlmc-devel at videolan.org
>> https://mailman.videolan.org/listinfo/vlmc-devel
>
> _______________________________________________
> Vlmc-devel mailing list
> Vlmc-devel at videolan.org
> https://mailman.videolan.org/listinfo/vlmc-devel


More information about the Vlmc-devel mailing list