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

Pawel Golinski golpaw1 at gmail.com
Thu Jul 21 20:07:51 CEST 2016


---
 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 ) );
+	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 );
+
+	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 );
+			}
+	}
+	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 );
+	}
+}
+
+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)



More information about the Vlmc-devel mailing list